Apache MyFaces Trinidad 1.2 Web Application Groundwork: Part 1

Exclusive offer: get 50% off this eBook here
Apache MyFaces Trinidad 1.2: A Practical Guide

Apache MyFaces Trinidad 1.2: A Practical Guide — Save 50%

Develop JSF web applications with Trinidad and Seam

$29.99    $15.00
by David Thomas | November 2009 | Web Development

In this article we develop the basic parts of the web application that serves as Trinidad sample web application. For example, login registration, user authorization, navigation, internationalization (18n), and polling are implemented and briefly discussed. We cover all these areas and learn how this can be practically solved in conjunction with Trinidad, Facelets, and Seam and provide further completing information wherever required.

Also, at the end of this two-part article by David Thomas, we deal with deployment using Seam-gen to rapidly deploy at each change of any file.

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):

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 xmlns="http://jboss.com/products/seam/pages"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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:

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.

Apache MyFaces Trinidad 1.2: A Practical Guide Develop JSF web applications with Trinidad and Seam
Published: December 2009
eBook Price: $29.99
Book Price: $49.99
See more
Select your format and quantity:

Authorization

We complete the authorization and provide each XHTML with an authorization lookup facility with regards to the edit or read-only permission, as well as authorizing a couple of mock users with specific roles. We define annotational and declarative authorizations by means of Seam. Let us briefly review these tasks.

Equipping each XHTML with authorization

As our page navigation is controlled by the purely programmatic Trinidad dialog alternative—as outlined in the foregoing—declaring authorization on a page level is less required. However, on a technical level, at least one authorization in the pages.xml makes sense:

<page view-id="*">
<begin-conversation join="true" />
<navigation>
<rule if-outcome="home" >
<redirect view-id="/home.xhtml" />
</rule>
</navigation>
<restrict>hasRightAccess</restrict>
</page>

Remember, authorizations are defined in our SampleIdentity which extends Seam's identity object, and so the definition of hasRightAccess is to be found there as well:

public boolean hasRightAccess()
{
return (hasRightAdmin() || hasRightReader() || hasRightEditor());
}

Thus, the access to any page is permitted as long as the user is either equipped with rights for administration, readership, or editorship. The process of authorizing a user is straightforward and outlined in the upcoming section.

User authorization

Now, to equip a user with authorization, usually either an LDAP or other data backed accesses would normally be required. We limit ourselves to show this in a mockup way and assign a couple of default users. This way, we can simply see where the authorization takes place and how it would work in principle:

@Name("authenticator")
public class Authenticator
{
@Logger Log log;
@In Identity identity;
public boolean authenticate()
{
log.info("now try authenticating #0", identity.getUsername());
//write your authentication logic here,
//return true if the authentication was
//successful, false otherwise
// simple example, of course, this is..but it shows the way it
// basically works ;)
SampleIdentity sampleIdentity = (SampleIdentity) identity;
if (sampleIdentity.getUsername().equals("DavidThomas") &&
sampleIdentity.getPassword().equals("Trinidad"))
{
sampleIdentity.addRole(SampleIdentity.roleEditor);
return true;
}
else if (sampleIdentity.getUsername().startsWith("anonym")
{
sampleIdentity.addRole(SampleIdentity.roleReader);
return true;
}
return false;
}

First of all, we allow anyone to pass the authentication as user with readership authorization as long as the user id is something like anonymous. Otherwise, we check the user specifically which, as I mentioned, would normally be through an LDAP or a database lookup. In our case, we mock it and check the user id for a specific user and the password for a specific input.

Technically this is framed by a couple of Seam techniques such as injecting the identity object that, at the time of entering the authenticate method, is setup with the login data passed in by the user through the login dialog. Next, we need to cast it to be able to access the extra methods that we used to refine it, namely the addRole and the role IDs that are specific for our application.

Finally, we follow Seam's authenticate method signature and return either true or false depending on the user being recognized by her or his credentials.

Internationalization (I18n)

We provide I18n support for two example languages (English and German) using Seam to easily access the messages resource property files by key lookup. When Facelet composition components are used, I18n support is encapsulated by the respective composition component's internal use of its component id to lookup the associated message, which is effectively done using JSTL. We briefly sum up the approaches for both cases in the upcoming topics.

I18n on single labels

This approach is used for any component that is directly applied, and therefore, is not encapsulated inside a Facelet composition component. For example, a Trinidad inputText component, we simply apply the Seam messages directly:

<tr:inputText columns="3" label="#{messages['teaUnit.teaUnits']}"
id="teaUnits" value="#{pageFlowScope.teaModel.number}" >

Regarding the EL expression, it is important to take care of the syntax; the identifier teaUnit.teaUnits must be stated within '', otherwise EL would try to evaluate it.

I18n on internal Facelet composition components

Again, the label plus id is used as a key for the lookup in the respective messages properties file depending on what the user's locale selection inside the login dialog results to. For instance, when we apply the following composition component:

<face:fieldSelect id="lgSelect" model="#{localeSelector.localeString}"
label="lang">

We provide a label attribute set to lang that together with the JSF id set to lgSelect, yields the key that is used to lookup the real label in the respective messages.properties because it is defined this way in the decorating JSTL code:

<c:set var="msg" value="#{label}.#{id}" />
<c:set var="msgLabel" value="#{messages[msg]}" />

The messages.properties then looks like this:

lang.lgSelect=Lengua

This results in Lengua being the select box label for the Spanish user or, at least, the user that has logged in with a selection of the Spanish locale.

Polling

We simply take advantage of Trinidad's poll component to automatically refresh the user's session so no timeout occurs as long as the browser client is running and showing a sample application's page. This, of course, is a simple solution that requires refinement on part of the specific user requirements for the respective application:

<tr:poll id="poller" pollListener="#{navi.refreshSession}" interval="3000" />

The poll tag declaration must fulfill the following two requirements:

  • It must occur inside a form component, otherwise it is automatically disabled by Trinidad
  • It must be applied with an ID, for example, poller

Furthermore, as can be seen in above example, it requires two attributes:

  • pollListener: This specifies a method binding referencing a PollEvent listener
  • interval: This specifies the time in milliseconds when a so-called PollEvent is raised

Following is an example for a PollEvent listener that is called in the fifth phase, the INVOKE_APPLICATION phase:

@Name("navi")
@Startup
@Scope(ScopeType.SESSION)
public class Navigator
{
...
/**
* does polling by handling Trinidad's PollEvent
* @param event PollEvent
*/
public void poll(final PollEvent event)
{
log.info("poller called at #0 int. #1",
event.getPhaseId(),
pollComponent.getInterval());
}
...
}

In the preceding example, we have chosen a very short interval to easily test the poll. So in the log output, we can see that the poller is called exactly as specified in the tag declaration:

09:15:33,440 INFO[controller] poller called at INVOKE_APPLICATION 5 int. 3000
09:15:36,967 INFO[controller] poller called at INVOKE_APPLICATION 5 int. 3000
09:15:40,525 INFO[controller] poller called at INVOKE_APPLICATION 5 int. 3000
09:15:44,004 INFO[controller] poller called at INVOKE_APPLICATION 5 int. 3000

Setting up the application with Seam-gen

In order to achieve a Seam-compatible web application project, the easiest and safest way is to profit from the project setup provided by the Seam project itself that is Seam-gen. Seam-gen is a command-line utility provided by Seam, among other things, like deployment of Seam-based projects and providing JPA mappings for an existing database. It allows generating a Seam application project in particular, which also supports a couple of IDEs such as Eclipse. This ensures that subtle issues, such as proper classpath loading, are working right from the start and thus, it is highly recommended, even more so because indirect errors are hard to cope with as they may possibly stem from a misconfiguration.

To be able to profit from Trinidad-specific and Facelet-specific IDE support, we choose and recommend the Eclipse IDE 3.4(+). Seam-gen supports the generation of an Eclipse skeleton project with all the Seam support that we want to take advantage of (security and authorization, conversations, and so on). This is simply achieved by typing the following command:

seam create-project

Note that before executing the preceding line, this input must either be entered on the command line or terminal by executing the following command:

seam setup

This command generates a build.properties file or directly provides it in a self-created build.properties file in the seam-gen directory of the distribution. Initially, more Trinidad-orientated setup is the following build.properties:

hibernate.connection.password=
workspace.home=java/eclipse/workspace/seamTestProject
model.package=com.test.SeamidadApplication
driver.jar=../lib/hsqldb.jar
action.package=com.test.TrinidadSeamidadApplication
test.package=com.test.TrinidadSeamidadApplication.test
database.type=
richfaces.skin=
hibernate.default_catalog.null=
hibernate.default_schema.null=
database.drop=n
project.name=SeamidadApplication
hibernate.connection.username=
hibernate.connection.driver_class=
hibernate.cache.provider_class=
project.type=war
icefaces.home=
database.exists=n
jboss.home=seamTestJBossHome
hibernate.dialect=
hibernate.connection.url=
icefaces=n

It is practical to set the property workspace.home to the path of the Eclipse workspace that is to be used for the test application. So, copying or moving the project of the Eclipse workspace can be avoided.

In this article, we do not want to deal with any database modeling or mapping, thus all the database-related indications are left out or avoided where possible. In our sample project, we will exclusively use viewer models (for example, java.util.List) to focus on the front-end side, the web tier.

Setting up an Eclipse project using Seam-gen

After generating the Eclipse skeleton, there is not much left to do to use it as an Eclipse project. Carry out the following steps to set up an Eclipse project using Seam-gen:

  1. Go to File | New | Project....|

  2. Then click on General | Next.

  3. Type in the name of the project in the Project name box(ensure that it is exactly the name provided in above build.properties).

  4. Finally, click on Finish.

As a result, the Seam-gen project is noticed by Eclipse that while setting up this project, executes the respective build scripts and thus deploying the test application to the application server, as configured by Seam-gen.

It is assumed that the open source JBoss Application Server is applied.

>> Continue Reading: Apache MyFaces Trinidad 1.2 Web Application Groundwork: Part 2


If you have read this article you may be interested to view :


Active Directory Disaster Recovery Expert guidance on planning and implementing Active Directory disaster recovery plans with this book and eBook
Published: June 2008
eBook Price: $35.99
Book Price: $59.99
See more
Select your format and quantity:

About the Author :


David Thomas

David Thomas is a developer and technical project manager of Java-based web applications and has well over 10 years of experience in various web technologies.

He began writing applications based on the Common Gateway Interface (CGI), HTML and Javascript, with a short Java Applets interlude.

The main occupation with Java began when Java took charge of the server. A series of Java Servlet applications were developed using an early, self-built Model-2 controller architecture. Java Server Pages (JSP) took hold for a rather long time and a couple of major, increasingly complex web applications were developed in combination with Struts.

Shortly after Java Server Faces 1.2 (JSF) emerged, began the development of a major JSF web application including the development of a high-level framework based on Apache My Faces Trinidad, Facelets and JBOSS Seam in the area of controlling. This project spawned a couple of sub projects so development continues up to the present day.

This is the author's first book which is highly influenced by the accumulated years of his experience in web technology.

Books From Packt


ICEfaces 1.8: Next Generation Enterprise Web Development
ICEfaces 1.8: Next Generation Enterprise Web Development

jQuery UI 1.7: The User Interface Library for jQuery
jQuery UI 1.7: The User Interface Library for jQuery

Apache Geronimo 2.1: Quick Reference
Apache Geronimo 2.1: Quick Reference

JBoss RichFaces 3.3
JBoss RichFaces 3.3

jQuery 1.3 with PHP
jQuery 1.3 with PHP

Apache CXF Web Service Development
Apache CXF Web Service Development

Grails 1.1 Web Application Development
Grails 1.1 Web Application Development

Tomcat 6 Developer's Guide
Tomcat 6 Developer's Guide


No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
F
m
2
b
G
W
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software