Apache Myfaces Trinidad 1.2 A Practical Guide (November

292

Transcript of Apache Myfaces Trinidad 1.2 A Practical Guide (November

Page 1: Apache Myfaces Trinidad 1.2 A Practical Guide (November
Page 2: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Apache MyFaces Trinidad 1.2A Practical Guide

Develop JSF web applications with Trinidad and Seam

David Thomas

BIRMINGHAM - MUMBAI

Page 3: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Apache MyFaces Trinidad 1.2A Practical Guide

Copyright © 2009 Packt Publishing

All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews.

Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the author, nor Packt Publishing, and its dealers and distributors will be held liable for any damages caused or alleged to be caused directly or indirectly by this book.

Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information.

First published: November 2009

Production Reference: 1031109

Published by Packt Publishing Ltd. 32 Lincoln Road Olton Birmingham, B27 6PA, UK.

ISBN 978-1-847196-08-8

www.packtpub.com

Cover Image by Vinayak Chittar ([email protected])

Page 4: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Credits

AuthorDavid Thomas

ReviewersCagatay Civici

Simon Lessard

Acquisition EditorRashmi Phadnis

Development EditorsRakesh Shejwal

Siddharth Mangarole

Technical EditorMehul Shetty

IndexerMonica Ajmera

Editorial Team LeaderAkshara Aware

Project Team LeaderLata Basantani

Project CoordinatorRajashree Hamine

ProofreaderJeff Orloff

GraphicsNilesh Mohile

Production Coordinator Shantanu Zagade

Cover WorkShantanu Zagade

Page 5: Apache Myfaces Trinidad 1.2 A Practical Guide (November

About the Author

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. This also included the development of major portal applications in the finance and banking sector.

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.

Apart from his work and the writing of this book, David Thomas likes to write music, sing his own songs, and accompany them on piano and guitar. Other hobbies of his are going on holidays, reading books, walking, swimming, making tea, and taking trains.

Furthermore, he is a firm believer in vegetarianism and the responsibility of each human being for her or his well-being and surroundings—in short, of acting locally while thinking globally.

Regarding this book he hopes it will be of great value to many people to enjoy an effective and efficient use of Trinidad.

I would like to thank my wife for her patience during the writing of this book.

Page 6: Apache Myfaces Trinidad 1.2 A Practical Guide (November

About the Reviewers

Cagatay Civici is the PMC member of open source JSF implementation Apache MyFaces and the project lead of popular PrimeFaces framework. In addition to being a recognized speaker in international conferences such as JSFSummit, JSFDays, and local events, he's an author and technical reviewer of books regarding web application development with Java and JSF. Cagatay is currently working as a consultant and instructor in the UK.

Simon Lessard has been using Java since 2000 with a focus first on game server development, and since 2005 on Web development, when he joined Fujitsu Canada team. Since then, he joined the Apache community working mainly on Apache Trinidad and Apache MyFaces 2.0, and also represents Fujitsu Limited on the JSF 2.0 Expert Group.

Page 7: Apache Myfaces Trinidad 1.2 A Practical Guide (November
Page 8: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Table of ContentsPreface 1Chapter 1: Introducing Trinidad 7

Background 7Overview of Trinidad 9

Characteristics of Trinidad 9General key criteria for the choosing of Trinidad 10Seamidad! Ease JSF development with Seam 13

Introduction and overview of Seam 13Application of Seam with Trinidad 14

Seam conversations and other context management 16Seam navigation 17Seam authorization 18Configuring Trinidad 24

Summary 28Chapter 2: Structuring and Building Pages with Facelets 29

Facelet page composition—templating with Facelets 30Using the template 34

Facelet composition components 36Creating the composition component 37The model attribute 38The visible attribute 39The msgLabel attribute 39The labelStyle attribute 40The required attribute 40The readOnly attribute 41The width attribute 41The margin attribute 41Declaring the composition component 42Applying the composition component 43

Page 9: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Table of Contents

[ ii ]

Using JSTL for further refinement 45Typical JSTL structures 45Things to be aware of when using JSTL and Facelets 47

Other tags to be aware of 48Experiencing Facelets in real life projects 48

Summary 49Chapter 3: Most Wanted Tags and Tag Attributes 51

Component library structure 51Trinidad’s XHTML tag library namespace (trh) 53Trinidad’s core tag library namespace (tr) 54

Standard tag attributes 57Standard tag attributes in tag groups 58

Attributes that occur in form and display tags 58Attributes that occur in command and navigation components 60Attributes that occur in large input and output components 60

The tag attributes for table, treeTable, and tree 61The tag attributes for table and treeTable 61The tag attributes for tree and treeTable 62The tag attributes for treeTable 63The tag attributes for tree 63

Summary 63Chapter 4: Rendering Pages Partially 65

Tag-based PPR 66Finding the trigger 67

Aspect 1: Ensure that the ID of the PPR trigger is correct 68Aspect 2: Ensure that the Trinidad configuration is correct 68Aspect 3: Ensure that the refreshed fields are reset 69Aspect 4: Ensure proper MVC setup 69Aspect 5: Ensure that the tag's partialTriggers work 70Aspect 6: Beware of using PPR with the rendered attribute 70

PPR with server-side caching by means of the Trinidad pageFlowScope 70PPR with a tr:selectOneChoice to refresh itself inside a component 71PPR with a tr:selectOneChoice component and a valueChangeListener 73PPR with a tr:selectOneChoice component and an actionListener 76PPR and the rendered attribute 79

Applying PPR naively 79The right way—a parent component with partial trigger 81

Java-side PPR using Trinidad's RequestContext 82Application of PPR from the Java-side 83

Step I: Define the PPR source 84Step II: Add the partial target 84

Summary 85

Page 10: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Table of Contents

[ iii ]

Chapter 5: Web Application Groundwork 87Navigation 87Trinidad's Dialog Framework 90

Programmatically creating a dialog 91Providing the data flow from dialog to dialog 91Returning from a dialog 92

Authorization 93Equipping each XHTML with authorization 93User authorization 94

Internationalization (I18n) 95I18n on single labels 95I18n on internal Facelet composition components 95

Polling 96Setting up the application with Seam-gen 97

Setting up an Eclipse project using Seam-gen 99Deployment 101

Trinidad-specific and Facelet-related changes to the project files 102Trinidad-specific changes to the Ant build script 105Deployment from Eclipse 106

Browser client setup 109Summary 111

Chapter 6: Building a Panel-based Content 113Where the Trinidad panel components live and what they support 113The accordion and showDetailItem components 115

How to play the panelAccordion 115The showDetailItem component—press to play an accordion key 116

The combination of accordion and showDetailItem 120An alternative to pure Facelets 122The content panel—same soul, different incarnation 123ControllerPanel keeps the panels under the same roof 124The toolbar facet 125

Skinning the panels 128Skinning the accordion and its children 128Skinning specific properties of the accordion's children 130Switching the skins on configuration level 130

Summary 132Chapter 7: Building a Form 133

Building a form 134Step I: Building the composition components 135

The fieldText component 135

Page 11: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Table of Contents

[ iv ]

The fieldDate component 137The fieldNumber component 139The fieldSelect component 142

Step II: Building the form 143Building a form with several panelFormLayout instances 145The approach 146

Step III: Decorating the form with Trinidad's form submission controls 148Processing of a part of a form by means of Trinidad subforms 149

Step IV: Adding a general message area 152Summary 152

Chapter 8: Growing a Tree 153Trinidad's tree components 153ChildPropertyTreeModel—Trinidad's out of the box model 155Creating a TreeNode Model 155Building up a tree model 157

Extending the ChildPropertyTreeModel to a Seam component 158Preparing the panels for navigation 159Applying the navigation component for basic navigation control 160

Creating the XHTML 161Using the nodeStamp facet to generate the tree 161Using a commandLink to create the clickable tree node 162Passing the node parameters to the navigation control 162

Extending the model-view tree couple 163Preparations for the new tree model 164

The properties of the AbstractTreeNode 164The AbstractTreeNode constructors 164New and modified helper methods 165The abstracted getters and setters 166The new TreeNode implementation is now short and easy 166The new tree node implementation for the new tree model 167

The new tree model—based on Trinidad's abstract TreeModel 168Test out the row disclosure by adding a RowDisclosureEvent listener 169Another tree content to better try tree traversal 169The getters to access the new state 170Tree traversal with Trinidad's container methods 171

The controller-enhanced tree models 175Testing internal navigation 176

Summary 177Chapter 9: The table and treeTable Components 179

The table component 179The table component in its most minimal usage 180Adding a selection listener 182

Page 12: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Table of Contents

[ v ]

Adding sorting 184Adding a button bar 185Adding detail data sub views and using a POJO data model 186Adding a search form and paging 188Adding banding and grids for better visibility 191Making use of JSF binding and Facelets for further encapsulation 191

Creating the XHTML: the reduction to a single line 194The treeTable component 195

The treeTable component in its most minimal usage 195Adding major table capabilities 196

Summary 200Chapter 10: The Chart Component 201

Where the chart component is and what it supports 201Bar charts 202

Stacking the bar chart 205Pie charts 207Area charts 209Line charts 211ScatterPlot charts 214Radar charts 215Funnel charts 219Gauge charts 219

Summary 221Chapter 11: Building a Wizard 223

Defining an abstract wizard model 223The properties of the abstract wizard model 223Constructors of the abstract wizard 224Providing the current step, action, and actionListener methods 225Providing control for the number of wizard steps 226Providing control for the current step index 226Providing step incrementation and decrementation 227Abstract class design aspects 227

Defining the concrete wizard 228Implementing the wizard's action listeners 228Implementing the wizard's navigation 229Implementing a step object 230Initializing a wizard instance 230The wizard's application inside the preparation controller 231Wizard implementation design aspects 232

Page 13: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Table of Contents

[ vi ]

Defining the XHTML side—the wizard's face 234Summary 237

Chapter 12: Dialogs—Pop-Up Your Web Application! 239Using the right scope: Seam or only Trinidad 240

How the conversation is kept during a Trinidad dialog 242Defining a dialog-enabled navigation control 243

Creating Trinidad dialogs in the navigation control 244Ensuring correct partial page rendering 245Standard context retrieval methods 247Calling the proper preparation method 248The resulting navigation point 249

Making a dialog-enabled tree control 251Creating concrete tree contents 252

Standard tree methods 253Providing navigational attributes 254

The tree's navigation method 254Revisiting the wizard—few additions make it pop-up 256Summary 258

Appendix: References 259Links to the Apache MyFaces Trinidad web site 259References 260

Chapter 1 260Chapter 2 260Chapter 3 261Chapter 4 261Chapter 5 261Chapter 6 261Chapter 7 262Chapter 8 262Chapter 9 262Chapter 10 262Chapter 11 263Chapter 12 263

Index 265

Page 14: Apache Myfaces Trinidad 1.2 A Practical Guide (November

PrefaceIn this book, you will learn how Facelets and Seam are used to get the most out of JSF. You start out by learning where Trinidad comes from and what its aims are. Additionally, you will also learn the often occurring tag attributes and, in particular, Trinidad's Ajax technology. You will implement login, authorization, navigation, internationalization, polling and browser issues with the help of these technologies. You will then use Seam-gen for deployment.

As you move through the book, you will develop a web application example where a series of selected Trinidad components are applied and their capabilities explored.

Finally, you will master the Trinidad dialog framework, a Trinidad key technology that allows the application of dialogs.

What this book coversChapter 1, Introducing Trinidad, introduces you to the Trinidad component library. We give a general idea of this component library, the areas covered by its components, and compare it to other libraries. Finally, the integration of Trinidad and Seam is discussed.

Chapter 2, Structuring and Building Pages with Facelets, explains Facelets as a basic means to structure and build pages using Facelet page composition, Facelet composition components, and JSTL.

Chapter 3, Most Wanted Tags and Tag Attributes, discusses the Trinidad tags and their attributes in a structured approach. You will gain an insight into the design of Trinidad allowing you to draw an efficient mental map of the library and make an effective selection and application of tags.

Page 15: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Preface

[ 2 ]

Chapter 4, Rendering Pages Partially, introduces you to the Trinidad's Ajax technology called PPR (Partial Page Rendering). PPR is inspected from two points of view—the pure tag-based partial rendering and the pure Java-side partial rendering techniques.

Chapter 5, Web Application Groundwork, teaches you how to develop the basic parts of the web application that serves as our Trinidad example. We present using Seam-gen to rapidly deploy after each change of any file.

Chapter 6, Building a Panel-based Content, deals with Trinidad's panelAccordion and showDetailItem components to show how they can be combined to build panel-based, panel-wise collapsible content.

Chapter 7, Building a Form, discusses the combinination of Trinidad's tags to Facelet composition components to build highly flexible and well-formatted forms, including messaging support.

Chapter 8, Growing a Tree, deals with Trinidad's tree components and models and exemplify their application. We present an effective shortcut that makes Trinidad's tree support an easy, and yet powerful, technology.

Chapter 9, The table and treeTable Components, gives an insight to Trinidad's table and treeTable components and exemplifies their application. We apply the components in an increasingly refined way, revealing most of their features one at a time.

Chapter 10, The Chart Component, deals with Trinidad's chart component and shows its application. You will learn to competently set up representation parameters, effectively achieving the intended representation focus and thus graphically materializing hidden information in an appropriate way.

Chapter 11, Building a Wizard, deals with Trinidad's components to implement a wizard and show their application. We present a solution to avoid an existing Facelet problem.

Chapter 12, Dialogs—Pop Up Your Web Application, discusses Trinidad's pop-up window techniques. We revisit Seam conversations to address the specific necessities for pop-up dialogs in Trinidad and Seam. We enhance the web application with a couple of pop-up windows including wizard pop-up support.

Appendix, References, provides us with useful references and links related to Apache MyFaces Trinidad.

Page 16: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Preface

[ 3 ]

ConventionsIn this book, you will find a number of styles of text that distinguish between different kinds of information. Here are some examples of these styles, and an explanation of their meaning.

Code words in text are shown as follows: "Add a general message area using tr:messages, Trinidad's standard component for this task."

A block of code will be set as follows:

<tr:panelFormLayout inlineStyle="width:#{inlineWidth}px;" labelWidth="#{labelWidth}" fieldWidth="#{fieldWidth}" rows="1" maxColumns="#{maxColumns}"> input11 input12</tr:panelFormLayout>

When we wish to draw your attention to a particular part of a code block, the relevant lines or items will be shown in bold:

<tr:panelFormLayout maxColumns="3" rows="1"> <�nput1><�nput�><�nput3><�nput�><�nput�><�nput�><�nput�><�npu<�nput1><�nput�><�nput3><�nput�><�nput�><�nput�><�nput�><�nput8> <�nput�><�nput�>

</tr:panelFormLayout>

Any command-line input or output is written as follows:

seam setup

New terms and important words are shown in bold. Words that you see on the screen, in menus or dialog boxes for example, appear in our text like this: "the check method has returned what it could find under the keyword Green, that is, Green Tea".

Warnings or important notes appear in a box like this.

Tips and tricks appear like this.

Page 17: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Preface

[ 4 ]

Reader feedbackFeedback from our readers is always welcome. Let us know what you think about this book—what you liked or may have disliked. Reader feedback is important for us to develop titles that you really get the most out of.

To send us general feedback, simply drop an email to [email protected], and mention the book title in the subject of your message.

If there is a book that you need and would like to see us publish, please send us a note in the SUGGEST A TITLE form on www.packtpub.com or email [email protected].

If there is a topic that you have expertise in and you are interested in either writing or contributing to a book, see our author guide on www.packtpub.com/authors.

Customer supportNow that you are the proud owner of a Packt book, we have a number of things to help you to get the most from your purchase.

Downloading the example code for the bookVisit http://www.packtpub.com/files/code/6088_Code.zip to directly download the example code.The downloadable files contain instructions on how to use them.

ErrataAlthough we have taken every care to ensure the accuracy of our content, mistakes do happen. If you find a mistake in one of our books—maybe a mistake in text or code—we would be grateful if you would report this to us. By doing so, you can save other readers from frustration, and help us to improve subsequent versions of this book. If you find any errata, please report them by visiting http://www.packtpub.com/support, selecting your book, clicking on the let us know link, and entering the details of your errata. Once your errata are verified, your submission will be accepted and the errata added to any list of existing errata. Any existing errata can be viewed by selecting your title from http://www.packtpub.com/support.

Page 18: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Preface

[ 5 ]

PiracyPiracy of copyright material on the Internet is an ongoing problem across all media. At Packt, we take the protection of our copyright and licenses very seriously. If you come across any illegal copies of our works in any form on the Internet, please provide us with the location address or website name immediately so that we can pursue a remedy.

Please contact us at [email protected] with a link to the suspected pirated material.

We appreciate your help in protecting our authors, and our ability to bring you valuable content.

QuestionsYou can contact us at [email protected] if you are having a problem with any aspect of the book, and we will do our best to address it.

Page 19: Apache Myfaces Trinidad 1.2 A Practical Guide (November
Page 20: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Introducing TrinidadThis chapter introduces the user to Apache MyFaces Trinidad—or, in short, Trinidad. Trinidad is a skinnable, Ajax-enabled, JavaServer Faces (JSF) component library that is highly adaptable to various requirements of today's modern web applications. It is most comprehensive in its functionality and consistent in its API interface and design. Trinidad's large component set arguably satisfies many, if not most, of the requirements that even large web applications nowadays have. Its Ajax framework makes sure pages are rendered in an efficient way. Their look and feel is easily switchable thanks to the underlying skin framework. Trinidad's consistent API interface and design makes JSF development become an effective experience.

This chapter will give a general idea of Trinidad. We will cover the following topics:

Areas covered by Trinidad componentsAn overview of its focus and advantagesCriterias to value the quality and the level of the offered componentsEased JSF development by combining Trinidad with the Seam web frameworkSeam used for navigation, context management, and authorizationTrinidad's configuration parameters

BackgroundTrinidad dates back to code development from the beginning of the 21st century. Oracle aimed at the development of a component-based web framework named UIX which would evolve into a core component library for JSF applications and further JSF frameworks themselves. Oracle's early decision to invest in JSF at a time when its future was not at all clear has turned out to be a gamble that paid off. Nowadays, JSF is one of the pivotal technologies when it comes to implementing middle-to-large-scale web applications.

Page 21: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Introducing Trinidad

[ 8 ]

Oracle's next decision, based on its commitment to the open source Java community, was to donate this framework, originally known as Oracle ADF Faces, to the Apache Software Foundation—which happened in 2006. A part of the development team remains at Oracle, thus ensuring design consistency. The Apache and Oracle team then concentrated on clearing the source from source dependencies to ensure the framework source only consisted of open source code. As an aside, Oracle ADF Faces development still continues, but it is now based on Trinidad.

On May 5, 2007, Trinidad left Apache's incubator and joined MyFaces as a subproject. Apache MyFaces is a project of the Apache Software Foundation that is responsible for the open source JSF implementation of the same name that includes a number of sub projects such as Trinidad.

By the end of June, Trinidad saw its first release 1.0.1 supporting JSF 1.1. On July 5, Trinidad 1.2.1, the version for JSF 1.2, was released. By the end of 2007 Trinidad started to become a component library with a frequent release cycle, about every two months on average. For more details, refer to the detailed release table in the Appendix, References. The Apache MyFaces mailing list with around 10 to 20 daily entries on Trinidad is another indication of an active user and developer community.

Milestone Version New Features2006 Trinidad Incubator Initial version with closed source bounds05/05/2007 Release as a MyFaces

subproject 1.0.1JSF 1.1 open source component library

07/05/2007 1.2.1 release (in parallel) JSF 1.2 open source component library09/06/2007 1.2.2/1.0.2 release Addition of aclient-side number converter

and skinning performance improvement 10/28/2007 1.2.3/1.0.3 release Panel improvements, DOM method

refinement, configuration improvement, icons and skinning improvements, Ajax improvements

12/10/2007 1.2.4/1.0.4 release EL improvement, skinning/CSS improvement, internationalization improvements

01/14/2008 1.2.5/1.0.5 release Sorting improvement, EL improvement, further conversion support

02/11/2008 1.2.6/1.0.6 release Improvements for skinning and rendering, application scope support,

03/16/2008 1.2.7/1.0.7 release Skinning improvement

Page 22: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 1

[ 9 ]

Milestone Version New Features05/21/2008 1.2.8/1.0.8 release Skinning improvement, file upload

improvement, pop-up dialog improvement, browser support, tree table improvement

08/07/2008 1.2.9/1.0.9 release Change Management improvements, panel improvement, demo and documentation updates, converter and input field improvements , browser support

Overview of TrinidadTrinidad is not just a JSF component library. It provides the developer with a modern web framework that focuses on comprehensiveness and a closed-world software design philosophy. This has two general advantages:

1. The user does not need to combine several component libraries. This avoids integration problems is mostly because of the exceptionally large number of components that Trinidad includes.

2. A high degree of consistency is encouraged. As a consequence, similar things are done in a similar way, similar attributes have consistent naming, side effects of other code sources are minimal, error growth is minimal, and so on.

Characteristics of TrinidadConcretely speaking, the following Trinidad features illustrate this approach's focus on comprehensiveness and closed-world software design:

Partial page rendering (PPR)—the built-in JSF-Ajax technology is part of practically all Trinidad tagsConsistent attribute naming, including sets of recurring attributes throughout Trinidad's tag universe (with different frequency levels of occurrence)A large number of JSF tags is available as a Trinidad version with refinements focused on Trinidad-specific technologies and support, for example, PPR, error or info messaging support, tooltips, labels, layout, and so onSkinning framework—each component is skinnable as well as its parts and attributes

Page 23: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Introducing Trinidad

[ 10 ]

Dialog framework—Trinidad's dialogs allow a web application to work with modal and nestable pop-up windows with no restriction as to its contentTrinidad also comes with its own scopes, for example, pageFlowScope to support dialog and page data flow

So now that we have an idea of Trinidad's character, the next obvious question is whether or not it would fit into one of the other JSF project. After all, many component libraries are available, then why should we make Trinidad our next project? It is not easy to make a choice if both variation and complexity are high.

If a component is missing, it is usually a better approach to rely on the addition of a JavaScript library, a self-written Facelet or JSF component than trying to integrate another component library that has such a component.

General key criteria for the choosing of TrinidadNo library can be the perfect choice for everyone, as software development projects are simply too different in their requirements. However, if we take a look at general criteria for the choice of a component library where Trinidad is strikingly strong, it will provide a clear and more detailed picture of Trinidad's strengths and help in making your choice.

So, in this section we will just give an idea which are the key criterias to the choice of Trinidad and why Trinidad is, if judged from these criteria, a very commendable choice. Further criteria for the choice of a JSF component library can be found in http://www.jsfmatrix.net.

Following are the criteria:

Maturity: Trinidad is a rather mature component library because it has been developed since the beginning of 2000 and has already passed a number of test cycles; moreover, its continuous development and commercial background all point towards a higher degree of maturity.

Page 24: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 1

[ 11 ]

Component range: With these criterias, we typically use the number of components as basic indicator. With well over 100 components Trinidad has a very comprehensive component collection. This collection extends from pure HTML support tags to really substantial components, such as a table viewer, that is, tr:table); a chart component, that is, tr:chart; refined select components such as tr:selectManyShuttle and tr:inputListOfValues; navigation orientation for example, tr:train, nested forms, for instance tr:form/subform; and so on.Interoperability: Trinidad works well with SUN's reference implementation (RI) of JSF and is well combinable with Seam, as we will see throughout this book. However, as is the case with all the other JSF component libraries, it is not well combinable with other JSF component libraries, which is expected to improve in JSF 2.0 with the introduction of standardized Ajax. However, the combination with JavaScript libraries, particularly in combination with Facelets, works very well with Trinidad and represents a worthwhile alternative.Framework character: This is an interesting criterion because it involves aspects like consistency of design and comprehensiveness which are much more the case when dealing with a framework. In comparison, a rather framework-less component library is Tomahawk where each component is much more on its own and can be used rather independently, which is why Tomahawk has a higher interoperability. Support: Support happens mainly through the mailing list, which is quite good considering that it is all free; alternatively, a commercial support by Oracle is surely possible if this is an option you wish to pursue.Facelet support: As already mentioned Trinidad works well with Facelets and is, in fact, the recommendation.Activity example (based on last build): Currently, several developers work on Trinidad, some of them at Oracle, also taking care of design consistency. The community is very much alive as indicated by Trinidad's high release frequency and mailing list traffic.Functional range (functional requirements fulfillment): Of course, this is extremely project-specific, yet the most important criterion as specific, often very singular requirements and their fulfillment, make the biggest difference. Simply speaking, the question to answer is to what degree the library's capability is to fulfill project-specific requirements out of the box? For instance, if a specific requirement is accessibility, refer to the last section of this chapter on configuration. Trinidad has built-in support that is practically unknown to other component libraries.

Page 25: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Introducing Trinidad

[ 12 ]

Adequacy: This is a criterion that is closely related to functional range, but more general in terms of the general design philosophy and the user interface guidelines that have materialized in the library. A good example is if the library is capable of supporting a purely keyboard-based navigation, which is the case for Trinidad, or if it is a library that is geared towards mouse-centered direct manipulation, such as JBOSS's RichFaces or SUN's Woodstock. Another example is mobile support, where Trinidad is compatible with a number of major mobile browsers such as Apple IPhone or Microsoft Windows Mobile (refer http://myfaces.apache.org/trinidad/devguide/mobile.html).Skinnability: A web application is skinnable if there is a mechanism whereby one is able to easily and consistently change a specific look and feel, that is the skin, by configuration. In Trinidad this is efficiently supported as part of css-based, component-wise definitions such as the messages component, which can be skinned individually, and the aspect-wise definitions. For example, global selectors, such as AFDarkForeground:alias to set the primary foreground color of the foreground color ramp, so that a couple of well-defined css files, one per skin, is enough to setup and interchange such a skin by configuration.Design quality: This can be measured by the usage flexibility of each component, which is actually very high as one can easily see by looking at the refined and consistently recurring control attributes that many tags have.Documentation: This is provided on the web site and, apart from a couple of broken links on the web site, fairly good. Refer to the Appendix for a list of working links.Browser and platform support: A couple of browsers and platforms are supported, the foremost ones currently are Firefox and Internet Explorer. For current information on browser compatibility, please visit http://myfaces.apache.org/trinidad/browsers.html. Trinidad is compatible with both JSF 1.2 and 1.1 and provides releases for both specifications.

A warning to everybody to avoid IE because of security leaks and the many bugs!

We have seen that Trinidad's framework character helps in various aspects when developing a JSF application. However, there are a couple of issues where Trinidad relies on JSF, and JSF itself is not refined enough to cope with them in an easy way.

Page 26: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 1

[ 13 ]

Seamidad! Ease JSF development with SeamTo be able to better concentrate on the Trinidad component library without having to deal with JSF intricacies and shortcomings, the Seam web framework was introduced. The areas are discussed where Seam comes very favorably into play, that is, scopes such as conversation context, navigation and authorization. Moreover, integration issues are also mentioned. Further details are discussed in the web application chapters.

Introduction and overview of SeamTrinidad focuses on the viewer side of development, providing concrete JSF components. Seam is a next-generation web framework that has its focus much more on the internal middle tier layer whose domain and controller objects can be managed by Seam to live as Seam objects. This makes it much easier to manage them inside the context of a web application. So the middle-tier covered by Seam involves the management and support for the following types of objects:

All kinds of controller objects, for example, a navigation controller that encapsulates Trinidad's dialog framework, which is covered throughout this bookModel objects which possibly include controller logic to some degree, for instance tree model controllers or a panel model, both to be covered in this bookDomain objects that represent the pure object-oriented mapping of database entities as Seam-managed entity beans which reach into the backend, something that is out of focus of this book

Therefore, Seam's emphasis is on providing an overall glue framework for all tiers, with a notable emphasis on the middle-tier. At the same time, this is the main reason why it comes into consideration to fill all the gaps and incongruities left by other frameworks including JSF and Trinidad.

Page 27: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Introducing Trinidad

[ 14 ]

The following image shows the application tiers and the framework responsibilities:

backendtier

middletier

web(frontend)

tier

clienttier

Seam Trinidad/Facelets

Therefore, to allow one to enjoy the advantages of both frameworks, the approach of combining both frameworks is well worth considering. Thus, for the middle-tier layer, where Trinidad rather leaves us to the mercies of JSF, we could take advantage of Seam. Note that, in the past, such a combination also meant some tedious integration work.

In the mean time, integration has been resolved up to a point where, arguably, no serious issues remain. Note that we will still find some integration issues, but we will also resolve them over the course of our Trinidad development sample.

All in all, it makes sense to profit from both frameworks and thus, in further combination with Facelets, which is discussed in the following chapter, we will achieve the current, most state-of-the-art JSF web framework combination.

Application of Seam with TrinidadSeam allows us to manage the following areas effectively:

Conversations and other context management: Seam introduces a conversation context, a new scope that is managed by Seam directly below the session context and that allows, for instance, keeping a possibly long-running context alive only while the domain is being worked on. For example, in operative systems a new file entry implies a new conversation that starts at the time when the file entry is set up by the user, and ends at the time when that entry is really committed and made persistent. Furthermore, all contexts, including the other usual web contexts, become easily manageable because Seam takes advantage of Java 5 and provides annotations that make objects available to contexts and components and allow transferring between them.

Page 28: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 1

[ 15 ]

Navigation: Seam further improves JSF by providing various navigational refinements that simplify and clarify navigation. For instance, JSF's usual faces-config.xml remains rather empty in favor of *.page.xml files that declare navigation page-wise with other, much clearer and simpler tags.Authorization: Seam includes its own authorization framework that can be used to implement a Java or Rule-based authorization system, the latter using JBOSS Rules. It not only supports simple things such as providing a central, self-refinable identity object updated by a self-provided login page, but also more refinement such as annotating the authorization of methods and objects so authorizations are seamlessly checked at method invocation time.

There are many more improvements that we will come across in the course of building our sample web application. But first, let us further illustrate the main areas where Seam comes into play. The following screenshot shows the login screen based on Seam support for internationalization and authorization:

Page 29: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Introducing Trinidad

[ 16 ]

Seam conversations and other context managementSeam has a couple of useful annotations, whereby one is enabled to annotate the desired context of objects as part of their declarations in the respective class source. The objects may be of any type, for example, controller or domain data objects. Mainly the following are applied:

@In(scope=ScopeType.<CONVERSATION|SESSION|PAGE|..>, required=<true|false>, value="<SeamName>"): This annotation enables the value of the variable's <SeamName> from the indicated context to be assigned to the annotated object, often from the current CONVERSATION, which is carried out by Seam's context management mechanism. The shortest annotation is simply @In where the object is taken from the first context it appears in a certain priority order, see below, either using the name indicated by the value parameter or the name of the object itself. The required parameter allows the injected object to be null if required="false", otherwise an exception is thrown.@Out(scope=ScopeType.<CONVERSATION|SESSION|PAGE|..>, required=<true|false>, value="<SeamName>"): Antonymically to @In, this annotation enables the annotated object's value to be assigned to the variable <SeamName> in the indicated context, which again is carried out by Seam's context management mechanism, often in the current CONVERSATION. The shortest annotation is simply @Out.@Name(<"SeamName">): This annotation is used to make an object to a Seam component; it needs to get a Seam component name so it can be addressed from other contexts. This annotation is precondition to using the aforementioned @In/@Out inside of a Seam component.

Note that both annotations presuppose an object and interaction design architecture to get the desired object value updates and readings at the right times. For our sample web application, we will use a simple architecture that applies web tier viewer models, thus leaving out project-dependent discussion of domain tier architecture, and use them as domain objects and Seam components as controller objects.

The controllers will use the @In and @Out annotation to date up conversation-bound domain objects by user-form interaction. In other situations, it may be that an injection or projection is required where no annotation-based injection or projection automation occurs. Alternatively, Seam provides Java-API-based manipulation by means of Seam's Contexts object and their getters and setters:

org.jboss.seam.context.Contexts.lookupInStatefulContexts().get("<Name>")org.jboss.seam.context.Contexts.lookupInStatefulContexts().set("<Name>")

Page 30: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 1

[ 17 ]

Alternatively, one may explicitly provide the context to lookup, for example, the conversation context:

org.jboss.seam.context.Contexts.getConversationContext().get("<Name>")org.jboss.seam.context.Contexts.getConversationContext().set("<Name>")

Furthermore, when using @In or @Out without further indication or the lookupInStatefulContexts method or to access an object or a component from a JSF page, one has to take the priority into account, whereby Seam tries to find an object in the various contexts from top to bottom:

Event context: Typically, this is the JSF request scope so event context objects are alive during the time the respective request is going on Page context: This is the JSF page scope level, practically analogous to the JSP page contextConversation context: As already mentioned, this is a special context provided by Seam to support stateful browser client or server interaction in an elegant and transparent waySession context: This is the usual HttpSession contextBusiness process context: Along with the conversation context, this is another Seam-specific context; it is provided for JBPM processes because of Seam's support of business process handling with JBPMApplication context: This is the usual web application scope as known in the servlet world

Seam navigationSeam navigation is organized in two levels:

1. pages.xml: This is the main file where all navigation is typically declared that is not on a single page-level, for example, general navigation for login, security, and error handling. Note that one could also declare the navigation of a single page in this file, but doing this for all pages means a large navigation that is potentially less manageable. However, it would all at least be -Struts-wise- in one place.

2. *.page.xml: This refers to the navigation for each JSF page. It is optional if only pages.xml is used.

Page 31: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Introducing Trinidad

[ 18 ]

Typically, each page is declared in a <page> block as follows:

<page view-id="JSF-Page-View-ID"> <navigation from-action="#{controllerName.methodName}"> <redirect view-id="JSF-Page-View-ID-2" /> </navigation></page>

The view-id identifies the page by its path plus its name, and always begins with a /, for example, /login.xhtml. Then, there is one or more navigation blocks that identify the action-triggered navigation. For instance, in the preceding example we see that on completion of a certain controller method, methodName, the view is redirected to another page—JSF-Page-View-ID-2. Although we will further elaborate on the navigation declarations, the basic navigation is going to be this way. The reason for this is that we want to keep any complexity away from the page definitions, for example, decision logic on where to navigate to will be kept in the respective controllers. The following image shows single page navigation, based on Seam's pages XML:

frontend tier (pages.xml)

step 2: redirectJSF-Page-View-ID JSF-Page-View-ID-2

step 1: action

controller

# {controllerName.methodName}

middle tier

Seam authorizationTo protect our pages from unwanted access, we will take advantage from the so called simplified mode of Seam security. This will spare us further authorization work that would distract us from our real target in this book.

Seam's simplified authorization provides objects for identifying, and authenticating, the user and setting up roles and rights. We will profit from this authorization framework which, by the way, may be quite easily extended to use a rule-engine, for example, JBOSS Rules, for more refined rule-based permission evaluations.

Page 32: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 1

[ 19 ]

Carry out the following steps to setup Seam authorization in a purely Java-based way without a rule-engine that suffices for our requirements to protect our pages depending on certain roles such as admin, editor, or reader:

1. Setup Seam's component configuration by modifying components.xml to use the Seam Security component. Here, we would use the namespace:

xmlns:security="http://jboss.com/products/seam/security"

And the schema:http://jboss.com/products/seam/security

http://jboss.com/products/seam/security-2.0.xsd

2. We then declare the object and its method to use for authentication: <security:identity authenticate-method="#{ authenticator.authenticate}" />

3. Now, we can implement the authenticator object, which is basically an override of the authenticate method:

@Name("authenticator") public class Authenticator { @Logger Log log;@In Identity identity; @In SampleSession sampleSession;

/*** write your authentication logic here, return true * if authentication succeeded otherwise false * @return true authentication succeeded */ public boolean authenticate() { SampleIdentity sampleIdentity = (SampleIdentity) identity; sampleIdentity.addRole("reader sampleSession.startSession( sampleIdentity.getUsername(), LocaleSelector.instance().getLocale() ); return true; } }

Page 33: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Introducing Trinidad

[ 20 ]

4. Now, implement the identity object, a specialization of Seam's Identity (SampleIdentity), and contain additional fields. Note that the imports and other minor declarations are skipped for readability of the essential material. Also be aware that we use a couple of annotations required by Seam to replace Seam's standard identity component (refer to the link of Seam's reference in the appendix for further explanation):

@Name("org.jboss.seam.security.identity") @Scope(ScopeType.SESSION) @Install(precedence = Install.APPLICATION) @BypassInterceptors @Startup @SuppressWarnings(value = "serial") public class SampleIdentity extends Identity { private static Set<String> authorizedMethod = new HashSet<String>(); private Set<String> roles = new HashSet<String>(); private final static String hasRight = "hasRight"; public final static String roleEditor = "roleEditor"; public final static String roleReader = "roleReader"; public final static String roleAdmin = "roleAdmin"; static { authorizedMethod.add( hasRight + "Editor"); authorizedMethod.add( hasRight + "Reader"); authorizedMethod.add( hasRight + "Admin"); } @Override public boolean addRole(String role) { roles.add(role); return super.addRole(role); }

5. We have defined a couple of simple rights and roles which illustrates the principle. Next, we need to override identity's evaluation method to be able to call our additional hasRight* methods:

@Override protected boolean evaluateExpression(String expr) { if (authorizedMethod.contains(expr)) { FacesContext context = FacesContext.getCurrentInstance(); MethodExpression method = context.getApplication(). getExpressionFactory().

Page 34: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 1

[ 21 ]

createMethodExpression(context.getELContext(), "#{identity." + expr + "}", Boolean.class, new Class[] {}); return (Boolean) method.invoke(context.getELContext(), new Object[] {}); } else return super.evaluateExpression(expr); }

6. Now we only have to describe the conditions to fulfill the respective rights which we simply reduce to checking if a suitable role has been assigned. This would be less simple in real life:

///////////// has rights behaviour /////////////// public boolean hasRightEditor() { if (!isLoggedIn()) return false; return hasRole(roleEditor); } public boolean hasRightReader() { if (!isLoggedIn()) return false; return hasRole(roleReader); } public boolean hasRightAdmin() { if (!isLoggedIn()) return false; return hasRole(roleReader); } public boolean hasRightAccess() { return (hasRightAdmin() || hasRightReader() || hasRightEditor()); } }

7. Finally, we setup the login.xhtml and apply Trinidad for the first time in this book:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" > <trh:html xmlns:tr="http://myfaces.apache.org/trinidad" xmlns:trh="http://myfaces.apache.org/trinidad/html" mode="strict" >

Page 35: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Introducing Trinidad

[ 22 ]

<trh:body><trh:body> <tr:panelFormLayout rows=»1» maxColumns=»1»> <tr:inputText label=»User Name» id=»username» value=»#{identity.username}» required=»true» /> <tr:inputText label=»Password» secret=»true» id=»password» value=»#{identity.password}» /> <tr:selectOneChoice label=»Language» id=»language» value=»#{localeSelector.language}» valueChangeListener=»#{localeSelector.select}»> <tr:selectItem value=»de» label=»German» /> <tr:selectItem value=»en» label=»English» /> <tr:selectItem value=»es» label=»Spanish» /> </tr:selectOneChoice> </tr:panelFormLayout> <tr:panelHorizontalLayout> <tr:commandButton action=»#{identity.login}» textAndAccessKey=»&amp;1:Login» /> </tr:panelHorizontalLayout> </trh:body> </trh:html>

Note that we will discuss all of these tags in detail in the upcoming chapters of this book. The following are a few points that need to be understood:

"trh" is the Trinidad tag library dealing with Trinidad's (X)HTML support tags."tr" is Trinidad's core tag library dealing with the main stuff provided by Trinidad.There are many tags known to XHTML and JSF that Trinidad provides its own version for. This is what has already been alluded to by mentioning Trinidad's design philosophy—to be fully supported by Trinidad. Those tags are provided in order to ensure their fully correct, and framework-consistent functionality, for instance the trh:body could be refreshed partially using PPR which would work, as all Trinidad tags support it apart from a few exceptions where it does not make sense.panelFormLayout allows one to build a form without taking much care as to its formatting. Trinidad does the formatting for us and even considers internationalization!Regarding navigation, the most important component here is notably the command button that calls Seam's identity object's login method that passes control to our authenticated method.

Page 36: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 1

[ 23 ]

The following screenshot shows the login page for Seam:

Now, we can secure pages and methods from unwanted access simply by annotating them before the respective method using:

@Restrict("hasRightEditor")private void insert() {...}

And inside of a page declaration in pages.xml or *.page.xml directly on the most upper block level:

<restrict>hasRightAccess</restrict>

After successful login, Seam automatically passes a information box, as shown in the following screenshot:

Page 37: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Introducing Trinidad

[ 24 ]

So if, for example, the user is not logged in, and a certain page's access is restricted with hasRightAccess, we get an error message on the current page an error is logged by Seam:

org.jboss.seam.secur�ty.NotLoggedInExcept�on

at org.jboss.seam.secur�ty.Ident�ty.checkRestr�ct�on(Ident�ty.java:18�)

at org.jboss.seam.nav�gat�on.Page.checkPerm�ss�on(Page.java:�18)

at org.jboss.seam.nav�gat�on.Page.preRender(Page.java:�38)

at org.jboss.seam.nav�gat�on.Pages.preRender(Pages.java:31�)

at org.jboss.seam.jsf.SeamPhaseL�stener.preRenderPage(SeamPhaseL�stener.java:��0)

at org.jboss.seam.jsf.SeamPhaseL�stener.beforeRenderResponse(SeamPhaseL�stener.java:��1)

at org.jboss.seam.jsf.SeamPhaseL�stener.beforeServletPhase(SeamPhaseL�stener.java:1��)

at org.jboss.seam.jsf.SeamPhaseL�stener.beforePhase(SeamPhaseL�stener.java:11�)

at com.sun.faces.l�fecycle.L�fecycleImpl.phase(L�fecycleImpl.java:���)

The following screenshot shows the error message produced by Seam which is declared in the pages.xml:

Configuring TrinidadThere are a few configuration options that are important, and possibly subtle enough, to warrant a mention here before going ahead with our sample web application. Two types of parameters can be distinguished by the location of their appearance, which is either in the web.xml or the more specific trinidad-config.xml.

Important Trinidad configuration parameters in the web.xmlThe following pair of parameters appear in the web.xml file and is of particular interest for the current development work and the pop-up dialogs:

Page 38: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 1

[ 25 ]

CHECK_FILE_MODIFICATION: This web.xml context parameter makes quite a bit of sense to set it to true during development and test cycles because it allows one to modify the css skin definitions on-the-fly, and to see the results of the changes immediately.ENABLE_LIGHTWEIGHT_DIALOGS: This web.xml context parameter is very important for our later exploration into Trinidad's modal pop-up dialogues; if not set to true we would get simple JavaScript-based browser window dialogs!

The following screenshot shows the comparison of a simple JavaScript-based browser window dialog (on the left) and a Trinidad lightweight dialog (on the right):

DISABLE_CONTENT_COMPRESSION: This is an important means to reduce the size of the resulting XHTML, which is achieved by using cryptically short names for the applied css styles. However, for development this parameter should remain false as the names practically become illegible and error analysis becomes difficult.DEBUG_JAVASCRIPT: Like the foregoing compression parameter, switching this one on disables compressed Javascript output so comments, spaces, and the original un-obfuscated naming becomes visible.

Page 39: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Introducing Trinidad

[ 26 ]

Important Trinidad configuration parameters in the trinidad-config.xmlThe rest of the more interesting parameters are located in Trinidad's own configuration file, the trinidad-config.xml:

<debug-output>: It is almost always a good idea to have this option activated throughout the development and test cycles as the rendered code is much more readable and understandable then and so easier to debug. <client-validation>: We keep this option DISABLED because we do not want to get into intricacies on the client side. We prefer a server-side approach that usually pays off by means of reliability and clearer architecture.<accessibility-mode>: This should be set to default so today's XHTML code is produced, such as input components using "label for" that make it more user-friendly. Furthermore, setting this parameter to 'screenReader' improves the look and feel under a screen reader; to remove any kind of accessibility support that optimizes output size, set this parameter to 'inaccessible'.<accessibility profile>: This allows further refinement of accessibility with values high-contrast to indicate the preference for a highly contrasting look and 'large-fonts' to indicate the preference for bigger fonts; both values can be set at the same time.<page-flow-scope-lifetime>: This specifies the maximum number of pageFlowScopes that are kept at the same time; pageFlowScope is Trinidad's own scope to keep models, and any other data, for Trinidad's pop-up dialogs.

Other configuration parametersFor the sake of completeness, let us briefly mention here the other, less generally crucial and more specifically valuable, parameters that may as well be applied:

Special parameters in the trinidad-config.xmlA series of parameters are provided that allow setting up help, internationalization, number formats, and one's own file upload processor class. These parameters have been explained as follows:

oracle-help-servlet-url: It allows setting the URL to link to a separate help system, for instance OHW, Oracle's Help for the Web.time-zone: It is used to set a default time zone independent of the respective browser.

Page 40: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 1

[ 27 ]

right-to-left: It is used to set an opposite language reading direction, for example, Hebrew. It defaults to false.currency-code: It is used to define a default for the format of currency fields in the case that a currency format is not provided within the respective Trinidad-based converter.formatting-locale: It is applied in converters by default if no other locale is explicitly used inside the respective converter.two-digit-year-start: It is used to set the assumed year default offset for two-digit year inputs, for example, 12/02/08.number-grouping-separator: It is used to define the character used as the separator of number groups.decimal-separator: It is used to define the character used as the decimal separator.uploaded-file-processor: It is used to indicate another class than the Trinidad default UploadedFileProcessor that is responsible for processing files to be uploaded. This class must implement Trinidad's file upload processor interface.

Special parameters in the web.xml for further optimizationFinally, there are a few further parameters devised for optimization under certain conditions:

CLIENT_STATE_METHOD: It serves to switch Trinidad's page state control that by default manages page state in the session scope, and uses tokens to distinguish several windows that display the same page. If this behavior is not desirable and page state is preferred to be managed on the browser client side, set this parameter to all. Otherwise to explicitly switch to the default, set it to token.CLIENT_STATE_MAX_TOKENS: It serves to explicitly set the number of tokens applied in Trinidad's page state control, the default being 15. If this value is surpassed, the page state for the oldest pages will not be available depending on the amount of the surpassed value. This is particularly relevant for pages accessed through the back button.CACHE_VIEW_ROOT: It is used to achieve an increase in PPR performance; Trinidad caches UIViewRoot, the JSF view tree, by default. However, this behavior might collide with other JSF frameworks. This is why this parameter allows switching it off.

Page 41: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Introducing Trinidad

[ 28 ]

USE_APPLICATION_VIEW_CACHE: When this parameter is set to true, Trinidad aims at higher scalability by caching the view state of initially rendered pages in the application scope. This saves a great deal of memory that would otherwise be spent across different page instances for each user; the default is false as an application's functionality may be broken by this optimization technique because it assumes the initial rendering of pages not to vary according to the user.CHANGE_PERSISTENCE: It is used to enable change persistence of component state that is modifiable by the user e.g. collapsing a tree node, or by clicking on detail display of a table row; the component state is usually kept in the session scope, which is the default implementation (refer to Trinidad's SessionChangeManager class), so the parameter value for enabling this component state persistence is 'session'.

SummaryIn this chapter, we have had our first encounter with Apache MyFaces Trinidad. We learned that it is not only a component library, but also a JSF framework. Tinidad, together with another web framework called Seam, results in the most state-of-the-art JSF web framework combination.

We have approached Trinidad from several angles. Historically, it developed from Oracle's component-based web framework UIX into a JSF component library with a strong framework character. Its software design follows a philosophy of comprehensiveness and closed-world design that make for a powerful JSF framework with a large component set and many underlying framework features. These features go far beyond the typical support given by a regular JSF component library—accessibility, mobile phone support, mouse-independent keyboard support, and built-in Ajax to name a few. Moreover, we learned about specific criteria to show where Trinidad is strikingly advanced in comparison with JSF libraries.

We introduced Seam as a second web framework applied to support JSF where Trinidad relies on it. Namely in navigation, scopes and general features to satisfy typical web application requirements, such as authorization which we have implemented in an exemplary fashion.

Finally, we saw which configuration parameters are supported by Trinidad to set up its various aspects such as internationalization, change management, optimization, and others—once again revealing Trinidad's comprehensiveness.

Page 42: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Structuring and Building Pages with Facelets

Facelets is a JSF view handler which has, by now, become kind of an official standard for JSF view technology devised for browser clients. As a further refined and extended version, it will become a part of the standard JSF libraries in the oncoming JSF version 2.0, including an option that allows using the current Facelets version. Originally, Facelets have been introduced to cover the main deficiencies of the default combination of JSF with JSP view technology. Therefore, problems regarding incompatibilities between the JSF and JSP life cycle could be fixed by using Facelets as a view handler that is natural to JSF. Moreover, various other enhancements, such as page composition techniques and composition components, have been introduced. Let's have a look at the main benefits of the newly introduced enhancements to Facelets:

Facelet page composition as a technique to compose one's pages as an assembly of partsFacelet composition components allow a simple yet effective encapsulation of reusable parametrized page parts that look and feel like JSF componentsUsing JSTL for further refinement of composition components

Actually, the developers who happen to know Tiles and Tapestry will feel quite at home with Facelets because the assembly of a page by Facelet page composition resembles Tiles, while creating and using a Facelet component is similar to creating and using a Tapestry component. Moreover, JSTL can be used within a Facelet component so that the developer can take advantage from tag-based control structures such as conditionals like choose-when-otherwise. Although declarative, it is somewhat comparable to Java inline code on a JSP page; however, on the one hand it appears encapsulated inside of components and, on the other hand, it acts inside specific phases of the JSF life cycle. So there is a big difference to JSP because the process is controlled by the Facelets view handler which is specifically

Page 43: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Structuring and Building Pages with Facelets

[ 30 ]

designed for JSF. Whereas in JSP, pages are simply compiled to create servlets that output exactly what appears on the page in the order of their appearance, in JSF there is a specific servlet called FacesServlet that puts a life cycle into action which essentially comprises, among other phases, the construction of a view tree of stateful components and its rendering. Generally, the Facelets view handler provides controls to take part in these major phases, providing templating and control flow means for the view tree construction as well as for the tree rendering.

The reader will see how the web application's basic structure is formed by Facelets. While the theory of composition components is presented here, their practice is shown in detail in the upcoming chapters.

Facelet page composition—templating with FaceletsUsually, the creation of pages is based on layout templates that make page creation more efficient as the assembly-wise rendering of page parts, that occur in several or all pages, is rendered by a specific engine that is focused towards such a task; in our case, Facelets. What is more, the developer is able to concentrate on the page-specific issues, repeated parts are not re-stated on the page, and the developer does not have to bother with such parts anymore if they are introduced as parts of a layout template.

Therefore, by using a couple of basic Trinidad tags, we go ahead and apply them as part of a general template that defines the layout of all the pages of our sample Trinidad web application:

<trh:html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:tr="http://myfaces.apache.org/trinidad" xmlns:trh="http://myfaces.apache.org/trinidad/html"

These name spaces tell us, and JSF, that we are going to apply the Facelets library ui for the structuring of the template and Trinidad's two JSF libraries tr and trh. It is no surprise that we start off by declaring the XHTML header part:

<trh:head> <title> <ui:insert name="title"> Please provide a title! </ui:insert> </title>

Page 44: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 2

[ 31 ]

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><script src= "#{facesContext.externalContext.request.contextPath}/ js/basicScript.js" type="text/javascript" />

We define a title area that is inserted by Facelets and contains the actual title; otherwise a warning is displayed with regards to a missing title. Some meta information is declared regarding the content to be XHTML in UTF-8 format. Furthermore, we declare a JavaScript library where application-specific JavaScript functions are kept, mostly only helper functions as we rather stress a rather server-side approach. Next, we define the main body's structure:

<trh:body initialFocusId="#{initialFocusId}"> <div class="body"><tr:form id="form"> <table width="990" border="0" cellpadding="0" cellspacing="0"> <tr> <td width="990" valign="top"> <div id="headpart"> <ui:insert name="header"> <ui:include src="header.xhtml" /> </ui:insert> </div> </td> </tr> </table>

Page 45: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Structuring and Building Pages with Facelets

[ 32 ]

The following screenshot shows the template main body including the header and the navigation part:

The first part of the main body's is, as expected, the header. This is where things like a logo and basic application functionality like login and logout are to be found. Here again we use Facelets which includes header.xhtml; the actual header part if it is not passed otherwise. The next part of the main body comprises of two parts. The first part is on the left hand side and is going to contain the navigation:

<table width="992" border="0" cellpadding="0" cellspacing="0"> <tr valign="top"> <td width="200" valign="top"> <div id="left" class="div"> <ui:insert name="navigation"> <ui:include src="navigation.xhtml" /> </ui:insert> </div> </td>

Again, Facelets allows the inclusion of a default navigation.xhtml if not otherwise passed. Finally, we reach the second part that consists of the actual content part:

<td width="792" valign="top"> <div id="center"> <!-- NOTE: allow any kind of additions --> <ui:insert /> </div> </td>

Page 46: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 2

[ 33 ]

</tr></table></tr:form></div><div class="footer"> Powered by <a href="http://jboss.com/products/seam">Seam</a>. Generated by seam-gen. Adapted for <a href="http://myfaces.apache.org/trinidad">Trinidad</a>, see <a href="http://www.packtpub.com">book</a>.</div></trh:body></trh:html>

The following screenshot shows the footer part of the template, including the empty main content:

As expected, this content part is placed next to the navigation on the right-hand side. It is declared in a way that does not restrict the actual content to be inserted.

The following screenshot shows the entire template:

Page 47: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Structuring and Building Pages with Facelets

[ 34 ]

This template defines several areas to be replaced by specific XHTML/JSF page sections. Precisely speaking, in the template these areas are declared by the following ui-prefixed Facelet tags:

<ui:insert name="NameOfArea"> DefaultContent </ui:insert> to define a named area to insert XHTML/JSF content starting at the position where <ui:insert name="..> is placed<ui:insert /> to declare an area that allows inclusion of any kind of XHTML/JSF content starting at the position where <ui:insert /> is placed<ui:include src="FileToInclude" /> to include any kind of XHTML/JSF file (this is practically the same as JSP includes)

The replacements are realized by applying the following elements:

<ui:composition template="NameOfTemplate"> to indicate which template is to be applied on the respective XHTML page<ui:define name="NameOfArea"> RealContent </ui:define> to declare the part of the respective XHTML page content that is going to be inserted into the indicated area (NameOfArea) as defined by its counter pair ui:insert

The respective XHTML content part that must be put at the position where <ui:/insert/> has been placedThe file to be included and storing it in a reachable location; typically, somewhere below the web content directory ("web_content")

Using the templateLet us have a look at what the template looks like when applied in a minimal way, that is, we leave out any specific entries and just use it to produce an empty page:

<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" template="layout/template.xhtml"/>

Page 48: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 2

[ 35 ]

The following screenshot shows a page that uses the template without passing any contents:

That is it! Of course, for an empty template page we would not even need the taglib declarations. However, we are going to fill the page out with just a bit of content next to see that the replacements work properly:

<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" template="layout/template.xhtml"> <ui:define name="title"> So I added a title! </ui:define> <ui:define name="header"> And here is a header!! </ui:define> <ui:define name="navigation"> Believe it or not, here is going to be my navigation! </ui:define> <p> And now for something completely different, the content..</p></ui:composition>

This template client takes advantage of all the areas in the template that were defined as replaceable. We provided a header title, and filled out the header with a bit of other text although we could have filled out a header.xhtml because it is defined in the template if no other input is provided by the template client. We did the same for the navigation area. Finally, we profited from the free, Facelet-untagged area that is passed to the template—where anything whatsoever found in the template client is instanced.

Page 49: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Structuring and Building Pages with Facelets

[ 36 ]

The following screenshot shows another template client using the sample template, this time providing concrete, yet simple contents:

Facelet composition componentsSomeone has said that Facelet composition components have come to the rescue of JSF. While this might be a bit exaggerated, it can nevertheless count as a remark that hints on the difficulty of writing one's own JSF components. If we compare the steps involved in the process of creating a JSF component with those of Facelet composition components, the latter is clearly much simpler to achieve. Though it is worth mentioning that JSF components also have their own benefits and one cannot solely judge by the amount of effort.

Only the following is required to build a Facelet composition component:

Create the composition component as an XHTML file using the Facelet composition tag <ui:composition> and the required namespaces for example, Trinidad and JSTLDeclare the composition component inside of a Facelet tag library XML file that defines its own namespaceApply the composition component, then deploy and restart the application (A simple update of above files does not suffice, a full deploy and restart is required)

Let us take a look at an example by creating a select box that includes all the wiring to its domain model and internationalization. Therefore, in the upcoming topic, we will go through above steps by looking at the select box example.

Page 50: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 2

[ 37 ]

Creating the composition componentWe define a namespace called "face" and a composition component called "fieldSelect".

It comprises of a panelLabelAndMessage component that allows using input components that do not need to be Trinidad components as its children while providing the label and messaging support usual to Trinidad input components. This way, the composition component may remain more flexible for later additions of such components and, moreover, it is even possible to use it in a way that suppresses the standard messaging next to the input component—for instance, showing messages in a pop-up message box instead.

The actual composition component 'fieldSelect' applies a selectOneChoice Trinidad component that allows the selection of an item from an item list that is enclosed by the mentioned panelLabelAndMessage component:

<ui:compositionxmlns="http://www.w3.org/1999/xhtml"xmlns:ui="http://java.sun.com/jsf/facelets"xmlns:h="http://java.sun.com/jsf/html"xmlns:f="http://java.sun.com/jsf/core"xmlns:trh="http://myfaces.apache.org/trinidad/html"xmlns:tr="http://myfaces.apache.org/trinidad"xmlns:c="http://java.sun.com/jstl/core"xmlns:s="http://jboss.com/products/seam/taglib">

<tr:panelLabelAndMessage rendered="#{visible}" label="#{msgLabel}" for="#{id}" labelStyle="#{labelStyle}" inlineStyle="display:none" showRequired="false">

<tr:selectOneChoice simple="true" showRequired="false" requiredMessageDetail="" label="#{msgLabel}" required="#{required}" disabled="#{readOnly}" value="#{model}" id="#{id}" contentStyle="width: #{width}px;margin-left:#{margin}px">

Page 51: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Structuring and Building Pages with Facelets

[ 38 ]

<ui:insert/> </tr:selectOneChoice>

</tr:panelLabelAndMessage></ui:composition>

Therefore, the following parameters may be passed to this composition component:

model: This is the model that keeps the selected item.visible: This serves to keep the display state of this component whether or not it is rendered.id: This is simply the JSF id; it may also be used to automatically find and use a model of the select items.msgLabel: This is the internationalized label of the select box.labelStyle: This is style-sheet-related inline definitions for the label.required, readOnly: These are used to setup the display. If required is true, Trinidad displays by default an asterisk before the label to denote that this is a required entry while readOnly="true" disables the select box. width and margin: These are used to setup the width and margin of the select box in pixels.

You need to be aware of the fact that the composition component applies <ui:insert/> inside the tr:selectOneChoice container tag, so that the client of this component is able to insert whatever select items are needed, such as the various supported languages.

Not all of the declared taglibs are used, but we will soon take advantage of most of them. Moreover, we declare those that may very possibly make sense in the near future, such as the Seam taglib. This is used to print out the Seam conversation id for test reasons.

There are a couple of Facelet parameters like msgLabel that do not seem to be passed, but this is something we will catch up with in the next section.

To further illustrate some of the more subtle attributes we will take a look at each of them applied in a simple example.

The model attributeAs already mentioned, this attribute serves to pass the actual model that is used behind the checkbox. A simple example is:

<face:f�eldSelect �d="lgSelect" model="#{localeSelector.localeStr�ng}"> ...

Page 52: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 2

[ 39 ]

Thus, the model is behind the getter or setter.LocaleSelector.instance().getLocaleString()/setLocaleString(String string);

It is simply a String where the actual selection is kept. This is not everything that is behind the model. Of course, the various items from which the actual localeString is selected need to be passed too. This is implemented by taking advantage of the <ui:insert/> definition. Therefore, regarding the model, the complete version of above example would look like this:

<face:fieldSelect id="lgSelect" model="#{localeSelector.localeString}"> <f:selectItems value="#{localeSelector.supportedLocales}" /></face:fieldSelect>

Note that according to the definition of tr:selectOneChoice we need a SelectItem[]. In the example, this is conveniently provided by Seam's localeSelector object that is provided out of the box with the getSupportedLocales() method yielding a SelectItem[] of the supported locales.

The visible attributeThe visible attribute allows controlling the component's rendered attribute. For instance, we can offer a language or locale selection only if the default locale is different from the browser client's locale, something we will take a closer look at later.

<face:f�eldSelect �d="lgSelect" model="#{localeSelector.localeStr�ng}" rendered="#{not facesContext.appl�cat�on.defaultLocale.d�splayLanguage.equals(localeSelector.locale.d�splayLanguage)}">

The msgLabel attributeThis attribute allows passing the key to the messages properties. For instance, in our language select box we could use:

<face:f�eldSelect �d="lgSelect" model="#{localeSelector.localeStr�ng}" label="lang">

in our messages properties if we take a look at the lang key of the German messages we find:

lang.lgSelect=Sprache

Thus, by using the combination of the label prefix and the JSF id we can simply make up a straight-forward convention of key definitions to easily find our internationalized labels.

Page 53: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Structuring and Building Pages with Facelets

[ 40 ]

The labelStyle attributeThis attribute allows setting up the inline style for our internationalized label, for example, styling it in a font of 14 points would work as follows:

<face:f�eldSelect �d="lgSelect" model="#{localeSelector.localeStr�ng}" labelStyle="font-s�ze:1�pt">

The required attributeTo get a visible indication with the default asterisk for inputs that are required in a form and to have the built-in Trinidad-based validation mechanism working, the composition component passes through the Boolean required attribute usual to all JSF input components, for instance:

<face:f�eldSelect �d="lgSelect" model="#{localeSelector.localeStr�ng}" requ�red="true">...

Note that to get the visual indication; the composition component needs to apply the standard Trinidad functionality to activate this standard behavior. There are two possibilities to achieve this. One possibility would consist of leaving out the panelLabelAndMessage component and reducing the composition component to the following simpler version:

<tr:selectOneChoice s�mple="false"

showRequ�red="true"

requiredMessageDetail="" label="#{msgLabel}" required="#{required}" disabled="#{readOnly}" value="#{model}" id="#{id}" contentStyle="width: #{width}px;margin-left:#{margin}px"> <ui:insert/> </tr:selectOneChoice>

However, it would become less flexible for future changes or additions. Alternatively, the second possibility is much more about preserving the composition component's structure and leaves the panelLabelAndMessage component intact:

<tr:panelLabelAndMessage rendered="#{visible}" label="#{msgLabel}" for="#{id}" labelStyle="#{labelStyle}"

Page 54: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 2

[ 41 ]

inlineStyle="display:none" showRequ�red="true"> <tr:selectOneChoice s�mple="true" showRequ�red="true" requiredMessageDetail="" label="#{msgLabel}" required="#{required}" disabled="#{readOnly}" value="#{model}" id="#{id}" contentStyle="width: #{width}px;margin-left:#{margin}px"> <ui:insert/> </tr:selectOneChoice></tr:panelLabelAndMessage>

Therefore, in the second possibility it suffices to switch on the showRequired attribute in both components to get the usual required indication.

The readOnly attributeTo obtain a disabled checkbox, we turn on this Boolean attribute that passes its value through to Trinidad's disabled attribute, for example:

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

The width attributeTo override the default width of the select box we can pass its width explicitly as follows:

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

This way we could, for instance, achieve an extra-long width of the select boxes which in some forms would probably look more in harmony with longer fields of the same column.

The margin attributeThe last attribute that is supported by our composition component allows setting up left margin, for instance:

<face:simpleFieldSelect id="lgSelect" model="#{localeSelector.localeString}" margin="100" ..> ..

The effect is a gap of 100 pixels that is placed between the label and the select box.

Page 55: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Structuring and Building Pages with Facelets

[ 42 ]

Declaring the composition componentHere, in the second step, we need to create a taglib.xml, which in our web sample application we name seamidad-facelets-taglib.xml. In the fieldSelect composition component must be declared:

<?xml version="1.0"?><!DOCTYPE facelet-taglib PUBLIC"-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN""http://java.sun.com/dtd/facelet-taglib_1_0.dtd"><facelet-taglib><namespace>http://www.packt.com/facelets</namespace><tag><tag-name>paramBuilder</tag-name><source>layout/faceletComponents/paramBuilder.xhtml</source></tag> <tag><tag-name>fieldSelect</tag-name><source>layout/faceletComponents/fieldSelect.xhtml</source></tag></facelet-taglib>

Additionally, we indicate another composition component called paramBuilder that which we use to decorate fieldSelect in order to preprocess parameters passed to fieldSelect or other components. We will take a look at that in the following section.

The XML structure is comprised of a container called facelet-taglib with a single namespace child and a series of tag children containers. Each tag's child container is made up of a tag-name child and a source child.

The taglib.xml declarations are rather easy to follow. First, we indicate the namespace that is used from normal taglibs (that is, the ones that are not Facelet taglibs) and followed by the actual series of composition component declarations, each one indicating its name and file path. For instance, the fieldSelect composition component must be declared by its name (tag-name) and its file path (source).

Next the taglib.xml needs to be declared in the web.xml to become known to the application:

<!-- Facelet Tag library --> <context-param> <param-name>facelets.LIBRARIES</param-name> <param-value>/WEB-INF/seamidad-facelets-taglib.xml</param-value> </context-param>

Page 56: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 2

[ 43 ]

As it can be seen, the declaration consists of a contextual parameter declaration in the web.xml, which is a typical web.xml parameter declaration as we know. For example, from the javax.faces.DEFAULT_SUFFIX declaration where we declare the XHTML suffix to be used as the suffix for our JSF pages.

In this case, we need to simply state the path to our Facelets taglib by setting the facelets.LIBRARIES parameter. This is recognized by Facelets to keep this kind of path, usually located in the WEB-INF folder where also our taglib xml file resides.

Applying the composition componentFinally, we apply the composition component on a page:

<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><ui:composition xmlns="http://www.w3.org/1999/xhtml"xmlns:s="http://jboss.com/products/seam/taglib"xmlns:ui="http://java.sun.com/jsf/facelets"xmlns:f="http://java.sun.com/jsf/core"xmlns:h="http://java.sun.com/jsf/html"xmlns:tr="http://myfaces.apache.org/trinidad"xmlns:trh="http://myfaces.apache.org/trinidad/html"xmlns:face="http://www.packt.com/facelets"template="layout/template.xhtml">

<ui:define name="body"><tr:form><tr:messages styleClass="message"/><tr:panelFormLayout> <face:f�eldSelect �d="lgSelect" model="#{localeSelector. localeStr�ng}" label="lang"> <f:selectItems value="#{localeSelector.supportedLocales}" /> </face:f�eldSelect></tr:panelFormLayout></tr:form></ui:define> </ui:composition>

Our body is conveniently instanced through Facelets page composition as part of the indicated Facelets template. It applies the fieldSelect composition component in a simple way without adding lots of the optionally available attributes, just applying the required attributes id, model, and label as explained earlier.

Page 57: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Structuring and Building Pages with Facelets

[ 44 ]

As we can see, it is located inside a form using a panelFormLayout component for proper form layout. This is discussed later in Chapter 7, Building a Form. The messages are shown by means of the Trinidad messages component instead of using messages shown next to the input field, which is default functionality of any Trinidad input component.

A simple comparison of the lines we encapsulated as the fieldSelect composition component with the ones we now use to reference it on above page reveals perhaps the most practical advantage of using Facelet composition components. We simply save ourselves a great deal or typing! Of course, on an architectural level the main advantage is that we now have a reusable component that we can specifically adapt and refine to be as powerful as needed.

For instance, we could get rid of the f:selectItems tag and make it part of the composition component itself by using fieldSelect component's id to retrieve the select items on a select items model of the application. Thus, the call of fieldSelect to select the locale language would be simplified to:

<face:f�eldSelect �d="lgSelect" model="#{ localeSelector.localeStr�ng}" />

This page also takes advantage of a couple of Trinidad tags that we will look at in detail in the upcoming chapter. Trinidad's form is used to specify a web form including a messages area and an automated layout area (panelFormLayout). In a later version of this template, we will move the form enclosure and messages area to the layout template so the actual syntactic overhead is further reduced for this client's templates. This is usually done in most real-life projects as well.

Finally, the third and last step is needed because the application needs to be redeployed and restarted on the application server since the taglib.xml has been changed. Otherwise, for existing composition components no full redeploy and restart is required. It suffices to date up the composition component's XML file on the application server, and therefore, development is fast and efficient with Facelet component development. With Facelets component, development is fast and efficient.

The following screenshot shows the Facelet fieldSelect composition component for locale choice:

Page 58: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 2

[ 45 ]

Using JSTL for further refinementOriginally developed for the now outlived JSP technology to support control structures on JSP pages, JSTL is a tag library that, when used in combination with Facelets, allows for better accessibility of control structures in composition components. Alternatively, one could also apply a combination of Java server-side coding and JSF EL to achieve similar results. However, the advantage here is that JSTL directly allows using control structures on the composition component's page definition. Therefore, control structures related to the composition component are not separated from the definition of the composition component and the developer has all the component-related code bundled together on one or several pages. This is quite easy to manage and maintain because no full redeploys or restarts during development are required.

Typical JSTL structuresThe following JSTL structures are typically used:

<c:if test="<EL-condition>"> ... </c:if>: It is used to check if a condition, given as a JSF Expression Logic statement, is fulfilled. For example, if the model has been passed #{empty model} and setup something as a consequence.<c:set var="<ParameterName" value="ParameterValue"/>: It is used to setup additional parameters, for example, <c:set var="isLocked" value="false"/>.With the choose structure we are able to formulate if-then-else-conditions:

<c:choose> <c:when test="<EL-condition>"> ... </c:when> <c:otherwise> ... </c:otherwise> </c:choose>

There is still more to JSTL, however, this is basically all we need to create a preprocessor component that is used as decorator of any Facelet composition component we define for a form field:

<c:choose><c:when test="#{not empty model}"><c:set var="value" value="#{model}" /></c:when>

Page 59: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Structuring and Building Pages with Facelets

[ 46 ]

<c:otherwise>Error: model must be passed!</c:otherwise></c:choose><c:if test="#{empty isLocked}"><c:set var="isLocked" value="false"/></c:if>

<c:set var="msg" value="#{label}.#{id}" /><c:set var="msgLabel" value="#{messages[msg]}" /><c:set var="wholeId" value="#{form}:#{id}" /><c:if test="#{empty required}"><c:set var="required" value="false" /></c:if><c:if test="#{empty readOnly}"><c:set var="readOnly" value="#{isLocked}" /></c:if>

<!-- set the width to a constant value if not passed --> <c:if test="#{empty width}"><c:set var="width" value="118" /></c:if>

Now, regarding the parameters, we can see the missing bits of fieldSelect. The internationalization is done automatically by looking up the respective messages properties file, and label plus id are used as a key for the lookup. The existence of the model is checked; otherwise an error message is directly displayed on the content page. Some parameters are created, derived from others so the user of this component does not need to pass them all. Note that the width is set to a constant value if it is not passed. This is a simple workaround to avoid a layout problem with panelFormLayout and ensures that all the applied select boxes are properly aligned, which is further discussed in Chapter 3, Most Wanted Tags and Tag Attributes.

In regards to the way to decorate fieldSelect component, this is quite easily accomplished by using the preprocessor as a composition component inside of the definition of fieldSelect:

<paramBuilder> .. </paramBuilder>

We do not even have to restate the passed parameters as they are still available for the preprocessor when fieldSelect is called.

Page 60: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 2

[ 47 ]

Things to be aware of when using JSTL and FaceletsFor the described simple usage of JSTL, there should not be much to worry about applying composition components that have such a restricted JSTL usage where it is only applied for parameter preprocessing as described.

However, things are not really always this simple. JSTL should always be used with some care in all other cases as intricate situations might arise, particularly when it is used in following constellations:

Container tags such as c:if and c:choose should avoid JSF children components unless the developer is fully aware of exactly when, in the JSF life cycle, these tags are executed, and how this impacts the JSF tree.The same holds for the inverse constellation. JSF container components should avoid JSTL tags as their children. This is potentially critical because it might collide with the life cycle phase order as, always to keep in mind, the JSF tree is built before the components are actually rendered.

In the first constellation, generally, we ought to apply id attributes for the respective JSF components, to make sure that between the JSF life cycle rendering phase, that is, the closing JST tree saving and the initial JSF tree reconstruction phase, no alteration of the JSF tree occurs. This is the way a replacement of components works.

Usually, the first constellation makes sense especially to increase performance, whereas the JSF-pure alternative, which works with the rendered attribute, does not influence the JSF tree creation. Only the state rendered is set, that is, the respective component still lives in the tree. For instance, by using c:if one is able to reduce a tree down its necessary components. A typical example would be authorization-based page construction where only certain components are part of the JSF tree depending on the user's authorization level.

The second constellation is problematic in case where dependencies between the JSF parent component and its children JSTL components exist. As already indicated, the reason is the natural order of the JSF life cycle. At the time when JSTL tags are executed, there is no state available that relates to the closing rendering phase where typically most of the actual component work takes place.

Page 61: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Structuring and Building Pages with Facelets

[ 48 ]

Other tags to be aware ofaware of ofYou need to be aware that not only JSTL tags require careful handling. The same holds for the application of some of the pure Facelets tags themselves, that is, those prefixed by ui:. Some of them belong to the same category as the JSTL tags, the list is as follows:

c:forEach, c:choose, c:set, c:if, c:otherwise, and so onf:facet, f:actionListener, f:valueChangeListener, and so onui:include, ui:decorate, ui:composition, and so onand any composition component

According to the Facelets documentation, they are all considered build-time tags. On the other hand, there are component tags such as ui:repeat, ui:fragment, and ui:component.

All in all, the situation has improved since the early days when JSF came out and JSP was used as its view handler. Many deficiencies have been removed by Facelets; a few still remain, as outlined above, but with proper care they can be avoided.

Let us briefly look at some other aspects related to JSF project life with Facelets.

Experiencing Facelets in real life projectsThere are a few further observations that are interesting throughout the usage of Facelets in JSF projects. While the templating aspects are all very transparent, the composition components have a potential trickiness that comes across with the application of the various Facelets tags.

Nevertheless, because of their ease, composition components tend to emphasize a rapid prototyping approach. However, this also means that in larger projects, project management needs to clearly organize a separate Facelets sub-project, with its own releases that must be put into coherence with main development. This way, the developers are not affected in the midst of their development by ever-changing components that break their code. Rather, at certain release points they are bound to check back on the changes of the latest composition components release and either adapt their code accordingly, or give feedback on errors.

Another area where further organization is requires is documentation, particularly when larger sets of composition components are built. In such a case, due to their nature and their possible composite interrelations, it may well happen that various tag attributes are widely repeated throughout those sets. Documenting these attributes would lead to lots of repetitions across various Tag Library Definition (TLD) files.

Page 62: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 2

[ 49 ]

A semi-organizational, semi-technical approach can be adopted by providing a TLD template from which the specific TLD files could be generated. On the other hand, this approach also has its drawbacks as an initial setup overhead is required. Moreover, the process itself is specific for the documentation of the composition components, so it is separate from the regular Javadoc generation.

SummaryIn this chapter, we have seen how Facelets, a view handler mechanism specifically developed for JSF, can be used to structure and build JSF pages.

We learned how Facelet page composition, the basic technique to compose one's JSF pages as an assembly of parts, works, and how Facelet composition components allow a simple yet effective encapsulation of reusable parametrized page parts that look and feel like JSF components.

We saw an example of a composition component and learned the steps to create it. Finally, we took a further look into Facelets features and saw that it is equipped with an implementation of JSTL that provides the most widely known tags of the former JSP tag library of the same name.

Moreover, we learned that some tags—such as the JSTL tags—have to be used with some care as some are only interfering in the JSF view tree construction phase, while others are focused on the rendering phase.

Finally, we looked briefly at real life experience with Facelets and gave a few hints on further things to be taken care of, particularly when composition components are applied.

Page 63: Apache Myfaces Trinidad 1.2 A Practical Guide (November
Page 64: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Most Wanted Tags and Tag Attributes

This chapter discusses the Trinidad tags and their attributes in a structured approach. The reader will gain an insight into the design of Trinidad allowing them to draw an efficient mental map of the library and an effective selection and application of tags. More concretely, the following topics are covered:

An overview of the XHTML-focused Trinidad namespace trhAn overview of the central Trinidad namespace trAn orientation and classification on the attributes supported by Trinidad

Component library structureTrinidad's approach to web technology is comprehensive: Aimed at full control of all the bits and pieces that make up a web application, little should be left that needs to be added. So based on such a closed world, Trinidad presents itself with a wealth of components and tags that even include very basic XHTML tags as replacements for the real XHTML originals. This is no radical replacement approach, rather it enables Trinidad to remain in full control of mechanisms such as partial-page rendering (PPR, also generally known as Ajax) that otherwise would need to deal with potentially incompatible libraries externally (refer to Chapter 1, Introducing Trinidad, for further discussion).

Page 65: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Most Wanted Tags and Tag Attributes

[ 52 ]

The following image provides an outline of Trinidad's structural package design:

<<Access, Derive>>

<<Access, Derive>>

<<Access, Derive>>

<<Access, Derive>>

<<Call>>

<<Call>>

<<Call>> <<Call>>

<<Call>>

<<Call>>

<<Import, Access, Instantiate, Derive, Call>>

<<Import, Instantiate, Call>>

org.apache.myfaces.trinidad.component.core.output

org.apache.myfaces.trinidad.component.core.nav

org.apache.myfaces.trinidad.component.core

org.apache.myfaces.trinidad.component org.apache.myfaces.trinidad.util

org.apache.myfaces.trinidad.component.core.data

org.apache.myfaces.trinidad.component.core.layout

org.apache.myfaces.trinidad.event

org.apache.myfaces.trinidad.component.core.input

Trinidad is divided into the following two namespaces:

tr: It is the usual tag library id that references Trinidad's core library tags. It's a large library of over 100 components ranging from layout components and navigational components, to special viewer components that all implicitly support skinning, partial-page rendering, popup dialogs, error or info messaging, and so on.trh: It is the usual tag library id that references Trinidad's XHTML support library tags, a small companion that offers alternatives for those XHTML tags that are usually applied to build XHTML structures, for example, XHTML tables.

Let us take a closer look at both namespaces. The upcoming image shows the core API's hierarchical structure. The tags are backed by two types of Trinidad classes—UIX* classes that deal with the JSF component requirements to implement specific JSF lifecycle processing methods, and Core* classes that deal with the specific properties (getters or setters).

Page 66: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 3

[ 53 ]

Trinidad’s XHTML tag library namespace (trh)Two groups can be distinguished from the trh namespace. The first one deals with the definition of an XHTML page and provides the developer with the following tags:

<trh:html>: It is used to define the whole XHTML page, analogous to <html><trh:head>: It is used to define the header, analogous to <head><trh:body>: It is used to define the main contents, analogous to <body><trh:script>: It is used to define a JavaScript to be executed, analogous to <script>

Page 67: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Most Wanted Tags and Tag Attributes

[ 54 ]

The second group deals with the layout of an XHTML table:

<trh:tableLayout>: It is used to define an XHTML table.<trh:rowLayout>: It is used to define an XHTML table line, analogous to <tr>; note that it can also be used to display an arbitrary line, particularly when elements need to be kept in one and the same line. Alternatively, it is particularly interesting to look at the tr namespace as it provides some less heavy structures free from table constructions, for instance panelGroupLayout with a layout set to vertical or a panelBorderLayout, both generating div structures instead.<trh:cellFormat>: It is used to define an XHTML table cell as part of an XHTML table.

The attributes of each tag are defined in a most consistent, and thus recognizable, way that will be seen in detail later in this book. By the way, there are also tags for the construction of framesets such as trh:frame in case anyone still wants to make use of framesets

However, before we deal with the attributes let us conclude this structural overview by a look at the organization of the functionality of the core tag library.

Trinidad’s core tag library namespace (tr)The following groups can be functionally distinguished which is also reflected in the packages structure of Trinidad's API (all beginning with org.apache.myfaces.trinidad.component; which has been left out here to avoid repetition). Note that, for completeness, we will also include information on the pure Java side as well as information on the few components that stem from the trh namespace:

Basic document composition tags from the core API: document, stylesheet, form, subform. poll also appears here although it is not a composition tag.Form input and display tags, components from the core.input API: inputText, inputDate, inputListOfValues, and so on.Command or navigation tags from core.nav that includes two tag types:

One that is focused on command tags that assumes a given form, presupposing the use of form and display tags from the foregoing group—commandButton, commandLink, goButton, goLink, and so on.The other deals exclusively with navigation: navigationTree, navigationPane, breadCrumbs, and so on.

°

°

Page 68: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 3

[ 55 ]

Large input and output component tags from core.data, for example, table, tree, and treeTable components.Layout component tags from core.layout, for example, all the swing-like panel tags, such as panelBorderLayout, panelHorizontalLayout, panelAccordion, showDetail, showDetailItem, and so on.Basic output components from core.output that are almost always used in a web application, for example, messages, outputText, outputLabel, spacer, statusIndicator, and so on.Model objects from core.model devised for various tags ; they provide the corresponding view models for their tag viewer counterparts, for example, SortableModel CollectionModeland RowKeySet for tr:table, ChildPropertyTreeModel for tr:tree and ChartModel for tr:chart.A couple of converter components from trinidad.convert equip JSF and Trinidad input components with powerful JSF conversion, that is, convertNumber and convertDateTime.Validator components from trinidad.validator equip JSF and Trinidad input components with powerful JSF validation such as range validation (validateDateTimeRange) and validation by regular expression match (validateRegExp).Events and event listeners from trinidad.event add new event types and listeners specific for Trinidad components such as those that support Trinidad's dialog framework, for example, commandButton to launch a popup dialogue using LaunchEvent, ReturnEvent, and ReturnListener. It provides only a few tags, but these can be very utile, for example, fileDownloadActionListener, resetActionListener, returnActionListener, and setActionListener.

There is a lot more to be found on the pure Java API side that either surfaces indirectly on the tag library as attributes, or is used implicitly by the tags themselves. Furthermore, there are utility classes and context support classes—RequestContext being probably the most prominent one because it offers a lot of functionality, for example, PPR from the server side. This is described in the upcoming chapter.

Page 69: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Most Wanted Tags and Tag Attributes

[ 56 ]

The following figure illustrates the Java side of things (it shows what the structure of some of the classes behind core.input look like):

The preceding figure is an outline of the core.input API hierarchy. Again, we can see the typical UIX* and Core* structure.

Finally, let us take a closer look at the tag attributes.

Page 70: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 3

[ 57 ]

Standard tag attributesWe begin by taking a closer look at the attributes that practically always occur, no matter which tag is actually involved.

As mentioned before, this occurrence is because of Trinidad's design which is noted by its consequent application of attributes that are shared by many different tags.

The following attributes occur almost always:

id: As it is already known from JSF itself, it ought to be set in most cases as it is used by Trinidad itself to identify the component. However, if it is not set by the developer, Trinidad sets up arbitrary, but not very legible, IDs.rendered: Typical for JSF; it is a Boolean attribute that allows setting if the component is to become part of the page sent to the client—in other words if it is considered by the Trinidad renderer.binding, attributeChangeListener: These are attributes that are practically never used because binding is an architecturally questionable JSF attribute as it incurs a traffic-intense, tight coupling between view and server-side model and is therefore not supported by Seam. On the other hand, attributeChangeListener is rather an internal Trinidad attribute to tell a Trinidad to re-render itself if renderer attributes of some other component have changed.

onmousedown, onmousemove, onmouseout, onmouseover, onmouseup, ondblclick, onclick: These are the usual JavaScript mouse event listeners, onclick is typically used to implement simple JavaScript confirm dialogues "Are you sure (Y or N)?".onkeydown, onkeypress, onkeyup: These are the usual JavaScript keyboard, single key event listeners and may be of interest although the attributes accessKey and textAccessKey are usually more practical.shortDesc: This attribute serves to set a short tool tip that is displayed when the user hovers with the mouse on the respective component.

°

°

°

Page 71: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Most Wanted Tags and Tag Attributes

[ 58 ]

inlineStyle and styleClass: The former attribute is very practical because it allows explicitly setting the style and overriding default style settings. However, it is cleaner to use styleClass, which is analogous to the XHTML style attribute, and define this explicit setup as a style sheet class in the style sheet (note that there are a couple of less frequent style attributes geared towards Trinidad-specific contents of component parts: contentStyle, labelStyle, listStyle, dateStyle, timeStyle, warnStyle, infoStyle, fatalStyle, errorStyle, defaultStyle,

stateStyle, userStyle).partialTriggers: This attribute serves to state the IDs of the components (separated by single spaces) that trigger a partial page refresh (PPR) which is discussed in the upcoming chapter.

Standard tag attributes in tag groupsLet's take a look at the attributes that almost always occur in certain tag groups (mentioned in the beginning of this chapter):

Attributes that occur in form and display tags This relates to the second tag group we learned in the earlier section named Trinidad's core tag library namespace (tr). The following Trinidad-specific attributes occur there:

label: This attribute serves to set the label of an input field; note that Trinidad support label indication, along with the respective input field, is also used for error or info messaging, for example, in the messages component.accessKey, labelAndAccessKey: Both attributes allow keyboard shortcuts for an input field, but labelAndAccessKey allows you to indicate the shortcut as part of the label. For example, label="&amp;9: date" activates the 9 key as keyboard shortcut for the respective input field (e.g. pressing Alt + Shift + 9 in Firefox). Note that, its analogon, textAndAccessKey in the command area.contentStyle: This attribute is used to set the style of the tag's content area, for example, the style used within input text's box.disabled, readOnly: These are Boolean attributes that both deactivate input fields, but disabled differs in its look by keeping the frame around the box.

°

°

Page 72: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 3

[ 59 ]

autoSubmit: If "true", it sends the enclosing form when this Boolean attribute's field is somehow manipulated, for example, by changing its entry and pressing tab or return. Note that this attribute must be "true" if partial page rendering is started from this attribute's field (refer to the upcoming chapter for detailed information).required, requiredMessageDetail, showRequired: The attribute required is a Boolean attribute to indicate if an input field entry must be provided by the user, and when it is not provided, it is allowed to indicate a custom message (requiredMessageDetail) and display a missing symbol (showRequired="true").simple: This is a Boolean attribute to control if Trinidad's label and messaging support is used. It also appears in the table tag.

A series of attributes in this group are those that stem from the core JSF tag libraries:

immediate: This is a JSF attribute and serves to have the respective input field converted, and validated before the process validator phase of the JSF lifecycle so that its possible server request may directly follow (apply request phase). For example, this occurs when using action listeners, which is a common practice.onblur, onfocus, onchange: These attributes expect the usual JavaScript handlers to be assigned.validator, converter: Both attributes serve to reference JSF's usual conversion and validation mechanisms, but validator differs in expecting a method call instead of a class. This is somewhat confusing, but JSF's core library supports the tag <f:validator validatorId="aValidatorClass"/> which can be very practically used inside of any Trinidad input field tag.value: This is JSF's standard attribute to assign the model behind the respective tag, for example, a view model or a real domain object.

Finally, in this group are listener attributes which come both from pure JSF and Trinidad:

actionListener: This attribute is based on the ActionEvent valueChangeListener: This attribute is based on the ValueChangeEventreturnListener: A Trinidad-specific listener called returnListener, is supported, and is used to indicate a listener method for a Trinidad Return Event when control returns from a Trinidad dialog (see respective dialogs chapter)

Page 73: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Most Wanted Tags and Tag Attributes

[ 60 ]

Attributes that occur in command and navigation components These are attributes that occur in the third tag group. We have learned about the command and navigation tags, to which these attributes are related, in the earlier section. Here we can see their attributes:

launchListener: This attribute serves to indicate a listener method that is called just before a Trinidad dialogue is displayed.partialSubmit: This is a Boolean attribute, which when set to "true" has the effect that its tag acts as a partial page rendering source (refer to the upcoming chapter for details).blocking: This is a Boolean attribute that, when true lets Trinidad block any other user input while the respective request is ongoing.textAndAccessKey: This is, as mentioned earlier, an attribute that allows assigning a keyboard shortcut. Note that its the power of Trinidad's consistent support of the keyboard that makes it a framework for all applications that heavily support keyboard users with minimal mouse activity.useWindow, windowHeight, windowWidth: These attributes are used to setup a Trinidad dialogue popup (useWindow="true") and its window size.

Attributes that occur in large input and output components These attributes come from the fourth tag group, the rather heavyweight input and output components as described in the beginning section. They can be further grouped into the following attribute categories:

component attributes specific for table, treeTable, and tree attributes specific for table and treeTable components onlyattributes specific for tree and treeTable components onlyattributes specific for the treeTable component onlyattributes specific for the table component only

In the following section, we will give an overview of each of the above attribute categories.

Page 74: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 3

[ 61 ]

The tag attributes for table, treeTable, and treeFirst, we come across a couple of listeners that deal with selection and disclosure:

A Trinidad-specific selectionListener serves to handle a SelectionEvent that is raised when the user selects a rowA Trinidad-specific rowDisclosureListener to handle a RowDisclosureEvent that is raised when the users clicks on a detail item or any other node that is closed

Next, follow the row-specific attributes:

selectedRowKeys: This is the set of all rows (or row indices) that are selecteddisclosedRowKeys: This is the set of all open nodes and rowsvar, varStatus: As known from JSF; note that varStatus serves to set if a model-based reference is used, for example, when returning a selected row or if an index is preferred

The tag attributes for table and treeTableA series of facets are supported that deal with the inclusion of developer own parts in certain areas of the views:

actions: This attribute is used to indicate any other action areas that are to be shown on the same line as Trinidad's built-in table or treeTable actions footer: This serves to setup anything in the footer area

header: This is to setup anything in the header area

A couple of specific listeners are provided to deal with sorting and range change:

A Trinidad-specific sortListener is provided to allow handling any SortEvent that occurs when the user clicks on the label of a column that has sorting activatedA rangeChangeListener is supported to handle any RangeChangeEvent that occurs when the user thumbs through the data when it is displayed page-wise

Page 75: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Most Wanted Tags and Tag Attributes

[ 62 ]

In connection with the sortListener table and treeTable, we need to provide the following attribute for setting up a selection mode:

rowSelection: This attribute serves to indicate if any selection at all is to be supported ("none"), and if so which type ("multiple" or "single")

autoSubmit: This is to enable partial page rendering which also sends the enclosing formemptyText: This is used to indicate any text that is displayed when there is no data to be obtained from the model

The following series of attributes deal with the general view setup:

rows: This is the number of lines to be displayed at oncesummary: This is used to indicate the purpose and structure of this component (only useful for non-visual output)rowBandingInterval, columnBandingInterval: These attributes serve to setup band style for easier reading and in particular, to indicate when which (horizontal, vertical, or both) band is changed (for example, every two lines)horizontalGridVisible, verticalGridVisible: These Boolean attributes are used to display a horizontal grid, vertical grid, or bothwidth: This attribute serves to define the overall width of this component

The tag attributes for tree and treeTableThere are just three attributes that are specific for both tree and treeTable:

nodeStamp: This facet allows to build the tree nodes by specifying a single looped node that allows us to build a tree in a highly dynamic way using an implicit loop (see the tree chapter for details)focusListener, focusRowKey: These attributes allow handling the focus when it is on a node, which raises a FocusEvent that may be handled by the indicated focusListener and that is accessible in the object indicated as focusRowKeyinitiallyExpanded: This is used to set if the component shows all the nodes when shown for the first time

°

°

Page 76: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 3

[ 63 ]

The tag attributes for treeTableThe treeTable tag is exclusively supported by the following attributes:

rowsByDepth: This allows us to set the maximum size of displayed nodes depending on the actual level(depth) by passing an array of integers for the depths that the developer wants to specify (for more details refer to Chapter 8, Growing a Tree)

rootNoteRendered: This is used to set if the root is rendered at all

The tag attributes for treeActually, there is only one attribute here that exclusively supports this tag:

allDetailsEnabled: This serves to set if the detail feature of a table is to be used, thereby allowing to display additional detail information per line

SummaryWe have seen what Trinidad is all about with regards to its component set. More concretely, we have first looked at the XHTML-focused Trinidad namespace trh that basically contains a component set for XHTML layout.

Furthermore, we looked at Trinidad's core namespace which is its tr JSF tag library. It contains a large component set with various types of components for basic document composition, form input and display, command and navigation, large and basic input and output, layout, models, converters, validators, events, and event listeners.

Finally, we looked at the attributes of all those tags and found out that a straight-forward orientation along tag groups is possible. This is thanks to Trinidad's framework character.

Page 77: Apache Myfaces Trinidad 1.2 A Practical Guide (November
Page 78: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Rendering Pages PartiallyThis chapter introduces Trinidad's Ajax technology called PPR (Partial Page Rendering). This technology serves to refresh a part of a page without having to entirely reload it. It is intrinsically built in to the JSF design and respects its life cycle relying on its complete execution.

Trinidad's PPR belongs to one of its key features that make it a real web framework. Built-in as part of all relevant tags and components, Trinidad offers a framework that is intrinsically Ajax-based—the term Ajax being arguably appropriate. Whereas PPR precisely reflects the meaning of this feature—one or several parts of a web page are re-rendered (refreshed) while others stay the same. In more detail, those parts that are re-rendered are the result of a refresh with a possible (in most cases) server request behind; for instance, a single method call or a whole form submit. The following topics will be covered in this chapter:

Tag-based partial page renderingIdentifying the trigger that causes the partial page refreshAspects to consider to make sure the requirements for proper working are fulfilledServer-side caching using a Trinidad-own contextReflexive PPRPPR and value change event handlingPPR and the rendered attributePPR from the Java side.

Page 79: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Rendering Pages Partially

[ 66 ]

Tag-based PPRPractically all relevant tags have built-in PPR support. The required attributes are always the following:

id: The id attribute identifies the component or tag that is the actual trigger, that is, the PPR event source of the PPR action. This is, of course, the usual JSF id attribute, but in this context it is vital because otherwise the component to affect the refresh would not be identifiable.partialSubmit or autoSubmit: These attributes must be set to "true" for the component to become a PPR trigger.partialTriggers: This attribute indicates those components with partialSubmit set to "true" that are the triggers for this attribute's component to be affected by a PPR action.

The following image shows the way these attributes work as part of the PPR technique:

partialSubmit="true"id=" "ID

partialTriggers = " "ID

partialTriggers = " "ID

UI component as PPR trigger

refreshed component

another refreshed component

further components to berefreshed

In the preceding image, you can see the mechanism. There is a component that acts as the cause for the refresh of certain other components. For example, a selection could have been done in the UI component with id="ID" because its partialSubmit attribute is set to "true". A change, such as a selection, causes all listeners—declared to be so by their partialTriggers attribute set to "ID"—to update their rendering due to the fact that they refresh themselves as a consequence. There is no limitation as to the number of refreshed components, or the number of their trigger components other than the number of components in the current JSF view tree. The applied design pattern behind PPR is the actually very simple and pervasive event-listener pattern, also known as the observable pattern. Concretely speaking, in this context we always need a PPR event that is raised by a Trinidad component or a tag that is observed by listeners that are attached to this event by setting their partialTriggers attribute to the id of the event raising component.

Page 80: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 4

[ 67 ]

Let us take a look at a simple example:<tr:commandButton id="pprEventRaiser" label="test" actionListener="#{controller.fetchData}" partialSubmit="true" /><tr:inputText partialTriggers="pprEventRaiser" value="#{dataModel}" />

A button labeled "test" acts as a PPR event source. If it is clicked, an action event and a PPR event are raised. First, the action event is handled. In short, after its action has been handled in JSF's application invoke phase the input field, made of a tr:inputText component, handles the PPR event as it has been identified by its partialTriggers attribute to be affected by a PPR from that button component. So after completing the given action handler fetchData, the following area (and only this area) of inputText is refreshed. Note that, partialSubmit must have been set to "true" to make the commandButton a PPR source (or synonymously, a trigger).

It's very effective, and yet simple, to use command buttons that change their label according to the state of domain objects; for example, if they are editable or only displayable. In this case, we can make reflexive use of PPR:

<tr:commandButton id="refreshesItselfButton" actionListener="#{controller.checkState}" partialSubmit="true" partialTriggers="refreshesItselfButton" label="#{commandButtonLabel}" />

So the id and partialTriggers attributes contain the same reference which is why any state change of this component's label through the checkState handler will result in a change of this button's label.

These are nice examples as the trigger references indicated by the partialTriggers attribute directly point to components on the same hierarchy of the component tree. When this is not the case, Trinidad provides a path mechanism that is described in the following section.

Finding the triggerIt may be that the trigger is located somewhere above the respective component to be refreshed which may lead to a trigger search. For such situations, Trinidad provides a kind of path support with the ":" notation to make the search more efficient.

The following two use cases are supported:1. The trigger is high above in the JSF component tree; in this situation

it probably makes most sense to have Trinidad begin searching at the very beginning which is denoted by adding a ":" as a prefix to the trigger indication in partialTriggers. For example:<.. part�alTr�ggers=":pprEventRa�ser" ../>

Page 81: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Rendering Pages Partially

[ 68 ]

2. The trigger is located very close-by, just a few levels above. To initially jump up one level :: is used. To jump to any level higher, which depends on the respective level being a naming container (for example, subform), requires an additional colon.

Of course, trigger and refreshed area should ideally be on the same level so trigger search is avoided and performance ensured.

There are only a few more aspects to consider ensuring a properly working PPR functionality, we will inspect these in the upcoming topics.

Aspect 1: Ensure that the ID of the PPR trigger is correctThe ID of the PPR trigger must be correct. This may seem trivial at first sight. However, the ID may sometimes be confusing and hard to find as it depends on the naming containers and the relative position of the area to be refreshed. Naming containers are found in the tr tag library. Typical components are tr:subform, tr:showDetail, tr: treeTable, and tr:table amongst others. The trh tag library has no naming containers.

To easily find out an ID on a given page, one may take advantage of the Firebug plugin if one develops for the Firefox browser (which I highly recommend due to the relatively low bug rate compared to Internet Explorer). Alternatively, for other browsers, one may use Firebug Lite which is also applicable for Internet Explorer. With just a click on Inspect, you are allowed to move around the content while the source code is shown respectively, this way allowing the developer to check the ID of a component.

Aspect 2: Ensure that the Trinidad configuration is correctThe Trinidad configuration must be fully correct; side effects may possibly hinder a proper PPR functionality. For instance, combining several component libraries is not such a good approach as PPR may possibly be compromised on. This is an issue that may easily rise up because by definition, PPR is the only built-in Trinidad components due to PPR's component-wise implementation. Thus, the usage of any additional libraries runs the possible risk of not being able to work with PPR. A very popular bad example is the combination of Trinidad with Rich Faces which incurs subtle incompatibilities that are hard to trace down.

Page 82: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 4

[ 69 ]

Aspect 3: Ensure that the refreshed fields are resetIf the field to be refreshed is used to submit a value before, for example, a search parameter, the field must be reset to null with respect to its submitted value. Alternatively, using the resetValue method of UIXEditableValue is also possible, although the application of its method as setSubmittedValue(null) is already sufficient.

A typical case of this behavior is when the field to be refreshed is used to pass a search parameter to a Trinidad dialog popup for selection which then is updated according to the entry that has been chosen there. In such a case, the submitted value must either be set to null by means of JSF's EditableValueHolder or its value must be reset by means of Trinidad's UIXEditableValue before the actual model is updated:

// alternat�ve 1Ed�tableValueHolder holder = (Ed�tableValueHolder) component;holder.setSubm�ttedValue(null);

//alternat�ve �((UIXEd�tableValue)component).resetValue();

The latter alternative is more complete because it also includes setting its validity to true among other things. A look in the implementation of Trinidad's resetValue() reveals:

publ�c vo�d resetValue(){ setValue(null); setSubm�ttedValue(null); setLocalValueSet(false); setVal�d(true);}

Aspect 4: Ensure proper MVC setupProper JSF MVC (Model-View-Controller) setup is another vital point. For instance, the model must be properly initialized to be updated later on in the course of a PPR activity. So if the model is not available on the page, PPR will not work correctly.

This may involve additional subtleties depending on the model's view component. So, for example, if Trinidad's outputText is used, a missing model will not be noticed by any error or exception output. However, if Trinidad's inputText is used, we receive an exception.

Page 83: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Rendering Pages Partially

[ 70 ]

Another potential variation of improper MVC setup is working with value change listeners (PPR with a tr:selectOneChoice component and a valueChangeListener) that we will see later in one of the following sections.

Aspect 5: Ensure that the tag's partialTriggers workThis is an issue that seldom occurs. If the component or tag that has the partialTriggers attribute is compromised by any defect, it is worthwhile to test, and workaround, by moving the partialTriggers up to its enclosing component (if any) to see if that works. To do this we simply add the partialTriggers attribute to the enclosing component and remove it from its original place. Then, if PPR works, there is a probability that there is a defect of the PPR functionality of the child component which should be filed to the Apache MyFaces Trinidad JIRA.

An example of this is the application of PPR on a showDetailItem component enclosed by a panelAccordion component. While partialTriggers does not work in certain releases, moving it up to the panelAccordion parent makes it work—although at the cost of probably unwanted refresh of other panelAccordion child components.

Aspect 6: Beware of using PPR with the rendered attributeIt is not possible to show or hide a component using PPR in combination with the rendered attribute unless the partialTrigger is placed on the component's parent rather than the component itself. This is due to the non existence of a DOM element with the component's clientId on the client side. We will look at an example in one of the upcoming sections, titled PPR and the rendered attribute.

PPR with server-side caching by means of the Trinidad pageFlowScopeAn interesting, and particularly efficient feature is the possibility of using PPR on the page with server-side caching by means of Trinidad's pageFlowScope. The following example illustrates this:

<tr:form> <tr:selectOneRadio value="#{pageFlowScope['choiceWhiteTea']}" label="Please Select White Tea:" autoSubmit="true" id="selectTea"> <tr:selectItem label="WhiteTea1" value="Lun Yin Whitest Snow"/> <tr:selectItem label="WhiteTea2" value="Silver Yunnan Greatest Tip"/>

Page 84: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 4

[ 71 ]

<tr:selectItem label="WhiteTea3" value="Pai Mu Mu Mu Tan"/> </tr:selectOneRadio> <tr:outputText value="Great Master, thou hast chosen: #{pageFlowScope['choiceWhiteTea']}" partialTriggers="selectTea"/> </tr:form>

The pageFlowScope is a Trinidad-managed scope for keeping state across pages or dialogs. When a new browser window or Trinidad dialog is opened, a new pageFlowScope is created. When a browser window or a Trinidad dialog is closed, the respective pageFlowScope is also closed. Otherwise, while the same Trinidad dialog and browser window is open, the same pageFlowScope is maintained. The number of supported pageFlowScopes can be configured by setting the page-flow-scope-lifetime parameter in the trinidad-config.xml file.

The pageFlowScope is found to be located directly below the session context, and is particularly designed for Trinidad pop-up dialogs among other areas, such as multi tabbing and back button support. Thus, this example is part of a Trinidad pop-up dialog. Trinidad pop-up dialogs are discussed in Chapter 12, Dialogs—Pop up Your Web Application!.

Let us look at another couple of examples for the application of tag-based PPR to see how it is used with other listeners. Basically, we will see its analogous usage despite some deviations influenced by the way a certain event is handled.

PPR with a tr:selectOneChoice to refresh itself inside a componentA classic showcase is an internationalized application's login dialog. The user changes the language and the selection area is supposed to adapt to the chosen language. We reuse the fieldSelect composition component from Chapter 2, Structuring and Building Pages with Facelets, and extend it to support the required PPR functionality:

... <tr:panelLabelAndMessage rendered="true" label="#{msgLabel}" for="#{id}" labelStyle="#{labelStyle}" inlineStyle="display:none" part�alTr�ggers="#{�d}"

showRequired="false">

Page 85: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Rendering Pages Partially

[ 72 ]

<tr:selectOneChoice simple="true" showRequired="false" autoSubm�t="true"

requiredMessageDetail="" label="#{msgLabel}" required="#{required}" disabled="#{readOnly}" value="#{value}" id="lgSelect3" contentStyle="width: #{width}px;margin-left:#{margin}px"> <ui:insert/> </tr:selectOneChoice> </tr:panelLabelAndMessage>...

The preceding highlighted lines are all that is needed to support the required refresh behavior. As soon as the selectOneChoice component is changed by the user, a PPR event is triggered which is listened to by the parent component that takes care of its label. Thus, the label is refreshed on any change of the language selection.

When this component is applied on the XHTML page it looks similar to what we have seen in Chapter 2, Structuring and Building Pages with Facelets:

<tr:panelCaptionGroup captionText="selectOneChoice component for I18n login "> <face:fieldSelect id="lgSelect" model="#{localeSelector.localeString}" label="lang"> <f:selectItems value="#{localeSelector.supportedLocales}" /> </face:fieldSelect></tr:panelCaptionGroup>

Therefore, apart from the caption rendering component panelCaptionGroup, nothing is new. The application is identical to the one presented in Chapter 2, Structuring and Building Pages with Facelets. In other words, we built PPR into the composition component. The developer who uses this component does not need to know anything to take advantage of its PPR ability. The following screenshot shows PPR inside a language selection composition component to refresh itself:

Page 86: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 4

[ 73 ]

PPR with a tr:selectOneChoice component and a valueChangeListenerObviously, PPR is always as good as the context in which it is embedded. However, not so obvious is the complexity incurred by the respective context. So this case is somewhat interesting as the valueChangeListener adds a complexity worth considering when using it in connection with PPR.

The issue is that the valueChangeListener runs in a different JSF life cycle phase which occurs much earlier than an action event listener. It actually runs before the process validation phase. This means that any model update is not available in the value change event listener!

To look at such an example we equip our selectOneChoice component with a valueChangeListener as follows:

... <tr:panelLabelAndMessage rendered="true" label="#{msgLabel}" for="#{id}" labelStyle="#{labelStyle}" inlineStyle="display:none" part�alTr�ggers="#{�d}"

showRequired="false"> <tr:selectOneChoice

Page 87: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Rendering Pages Partially

[ 74 ]

simple="true" valueChangeL�stener="#{controllerInteract�on.doValueChange}"

showRequired="false" autoSubm�t="true"

requiredMessageDetail="" label="#{msgLabel}" required="#{required}" disabled="#{readOnly}" value="#{value}" id="lgSelect3" contentStyle="width: #{width}px;margin-left:#{margin}px"> <ui:insert/> </tr:selectOneChoice> </tr:panelLabelAndMessage>...

If we look at a log output of a situation where such a selectOneChoice component with a built-in value change event listener as component lgSelect2 is applied, we can observe the following fact:

1�:�1:�1,0�3 INFO [ControllerInteract�on] *** doValueChange called:ANY 0 on component lgSelect�

1�:�1:�1,0�� INFO [ControllerInteract�on] doValueChange called w�th �nputF�eld:any value

ANY:0 is the phase id which reflects that a value change event handler doValueChange on a selectOneChoice component lgSelect2 runs before the process validation phase. Furthermore, by a look at the doValueChange method we can see that the value of a pageFlowScope object called inputField (which is accessed by Trinidad's RequestContext object presented in the following section) was set with a value of any value and then modified by prefixing it with a !!:

public void doValueChange(ValueChangeEvent arg0) { // TODO Auto-generated method stub log.info("*** doValueChange called:#0 on component #1", arg0.getPhaseId(), arg0.getComponent().getId()); Map<String,Object> map = RequestContext.getCurrentInstance().getPageFlowScope(); log.info("doValueChange called with inputField:#0", map.get("inputField")); map.put("inputField", "!!"+map.get("inputField"));}

Page 88: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 4

[ 75 ]

Next, we see that yet another component with a value change event listener is also called:

1�:��:0�,��� INFO [ControllerInteract�on] *** doValueChange called:ANY 0 on component testInput

1�:��:0�,��� INFO [ControllerInteract�on] doValueChange called w�th �nputF�eld:any value

On the XHTML, we see that the PPR trigger is properly declared to respond to the selectOneChoice component lgSelect2, as follows:

<tr:inputText id="testInput2" partialTriggers="lgSelect2" autoSubmit="true" simple="true" value="#{pageFlowScope.inputField}" valueChangeListener="#{controllerInteraction.doValueChange}" />

Interestingly enough, despite setting it to !!any value, it does not have the changed value but the original value, any value. As already mentioned, this is because no model update phase is run. Thus, the exclusive use of value change event listeners in connection with PPR could lead to the wrong conclusion that PPR does not properly work because the model is not updated. But the culprit here is the type of listener used, not PPR. This can be seen even more clearly when several value change event listeners are used which all call the same method doValueChange:

�0:�0:��,1�3 INFO [ControllerInteract�on] *** doValueChange called:ANY 0 on component testInput�

�0:�0:��,1�� INFO [ControllerInteract�on] doValueChange called w�th �nputF�eld:any value

�0:�0:��,1�8 INFO [ControllerInteract�on] *** doValueChange called:ANY 0 on component testInput

�0:�0:��,1�8 INFO [ControllerInteract�on] doValueChange called w�th �nputF�eld:!!any value

�0:�0:��,1�3 INFO [ControllerInteract�on] *** doValueChange called:ANY 0 on component lgSelect�

�0:�0:��,1�3 INFO [ControllerInteract�on] doValueChange called w�th �nputF�eld:!!!!any value

We can see how the inputField is growing with each call of doValueChange. However, nothing of this is refreshed by PPR; the field remains the same. We can see how aspect 4 (proper MVC setup) has been ignored.

Page 89: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Rendering Pages Partially

[ 76 ]

PPR with a tr:selectOneChoice component and an actionListenerIf we want to use the selectOneChoice component with a proper MVC setup, we can quite easily do so by enriching the above fieldSelect composition component through the use of the following effective combination of JavaScript, ActionEvent handling and PPR:

... <tr:panelLabelAndMessage rendered="true" label="#{msgLabel}" for="#{id}" labelStyle="#{labelStyle}" inlineStyle="display:none" partialTriggers="#{id}" showRequired="false"> <tr:selectOneChoice onchange="document.getElementById('#{formName}: th�sButton#{�d}').cl�ck()" simple="true" showRequired="false" autoSubmit="true" requiredMessageDetail="" label="#{msgLabel}" required="#{required}" disabled="#{readOnly}" value="#{value}" id="#{id}" contentStyle="width: #{width}px;margin-left:#{margin}px"> <ui:insert/> </tr:selectOneChoice> </tr:panelLabelAndMessage> <tr:commandButton part�alSubm�t="true" �nl�neStyle="v�s�b�l�ty:h�dden" �d="th�sButton#{�d}" text="Subm�t" act�onL�stener="#{controllerInteract�on.processAct�on}" />...

Page 90: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 4

[ 77 ]

Now that the new additions are highlighted—we add an onchange attribute to include a short JavaScript to access an invisible commandButton component to click it. This way, we create an ActionEvent that is handled by the following action event handler:

public void processAction(ActionEvent arg0) { log.info("*** processAction called:#0 on component #1", arg0.getPhaseId(), arg0.getComponent().getId()); Map<String,Object> map = RequestContext.getCurrentInstance().getPageFlowScope();; log.info("processAction called with inputField value:#0", map.get("inputField")); map.put("inputField", "!!"+map.get("inputField"));}

Apart from its action event signature, this method is practically identical with the foregoing value change event listener. Practically the same log is produced and the pageFlowScope object inputField is accessed and modified in the same way. The following screenshot shows PPR with proper MVC setup (the inputText value keeps growing):

Page 91: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Rendering Pages Partially

[ 78 ]

However, now if we look at the log output, we can see that the model is properly updated and thus, PPR is also properly working and the form is refreshed as expected.

1�:��:1�,80� INFO [ControllerInteract�on] *** processAct�on called:INVOKE_APPLICATION � on component th�sButtonlgSelect

1�:��:1�,80� INFO [ControllerInteract�on] processAct�on called w�th �nputF�eld value:any value

1�:��:�0,��0 INFO [ControllerInteract�on] *** processAct�on called:INVOKE_APPLICATION � on component th�sButtonlgSelect

1�:��:�0,��0 INFO [ControllerInteract�on] processAct�on called w�th �nputF�eld value:!!any value

As expected, the inputField keeps growing its prefix !! from request to request up to the value !!!!any value after above two requests; whereas, in the preceding example, it was growing within a request without being updated to the model, thus without any effect. With an action event listener, PPR is now effective and reflects the latest state of the model on the respective, partially triggered input component. The following screenshot shows the selectOneChoice with PPR and actionListener on an inputText component after two requests:

In JSF, the original use of a value change event listener was for validation of its input only.

However, the above applications are possible and serve as an interesting example of how things can get complicated in connection with PPR. Nevertheless, the complexity is not the fault of the PPR technique itself, rather of such contexts in which it is embedded.

Page 92: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 4

[ 79 ]

PPR and the rendered attributeTo deal with components that are to be rendered by PPR depending on certain states one has to take the limitation into consideration that has been pointed out in aspect 6. It is not possible to show or hide a component using PPR in combination with the rendered attribute unless the partialTrigger is placed on the component's parent rather than the component itself. A clear example on this is a real-life case that is only displaying to the user something to select—in case certain client conditions are given. For instance, if we enrich our selectOneChoice composition component fieldSelect with a dynamically passed rendered attribute we could offer the language choice for our login, depending on the browser client not having the default language locale configured in the JSF application. Otherwise, if the two are identical, no language choice is required and we could hide the language choice component.

Applying PPR naivelyLet us first try and do it as if we did not have above mentioned limitation. Then, we would simply enrich our fieldSelect composition component by a dynamically passed rendered Facelet parameter:

... <tr:panelLabelAndMessage rendered="#{rendered}"

label="#{msgLabel}" for="#{id}" labelStyle="#{labelStyle}" inlineStyle="display:none" part�alTr�ggers="#{�d}"

showRequired="false"> <tr:selectOneChoice simple="true" showRequired="false" autoSubm�t="true"

requiredMessageDetail="" label="#{msgLabel}" required="#{required}" disabled="#{readOnly}" value="#{value}" id="lgSelect3" contentStyle="width: #{width}px;margin-left:#{margin}px"> <ui:insert/> </tr:selectOneChoice> </tr:panelLabelAndMessage>...

Page 93: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Rendering Pages Partially

[ 80 ]

Next, we would pass the preceding described condition on when to provide language selection in our login page:

<face:fieldSelect id="lgSelect" model="#{localeSelector.localeString}" label="lang"rendered= "#{not facesContext.application.defaultLocale.displayLanguage. equals(localeSelector.locale.displayLanguage)}"><f:selectItems value="#{localeSelector.supportedLocales}" /></face:fieldSelect>

Therefore, when the default locale setup in the faces-config.xml is equal to the currently selected language on the browser client, this language is supposed not to be rendered.

However, despite the reflexive PPR setup that is built-in to the composition component which worked fine so far, nothing happens when choosing the same language as the default one, as can be seen in the following screenshot:

Not even the label is properly updated anymore, it remains in English. However, from the outputText lines in the caption group default and selected language that have been added for better clarity, we can see that both are now identical and thus the oneSelectionChoice component should not have been shown in the first place! The following are the added outputText components to better see what is going on:

<tr:panelCaptionGroup captionText="default and selected language"><tr:outputText value="default Language:#{facesContext.application.defaultLocale. displayLanguage}" partialTriggers="lgSelect "/><br/><tr:outputText value="selected language:#{localeSelector.locale. displayLanguage}" partialTriggers="lgSelect"/></tr:panelCaptionGroup>

Page 94: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 4

[ 81 ]

We can see the currently selected language that is output by the second tr:outputText component and the default language displayed by the first tr:outputText component.

As already mentioned, the reason for this failing behavior is the lack of a DOM component with the component's clientId.

The right way—a parent component with partial triggerNow what can we do to make it work? It is actually quite easy, particularly in this case. We need a Trinidad parent component that is equipped with PPR. Because the parent component panelCaptionGroup is just such a type of component, we only need to activate it partialTriggers appropriately:

<tr:panelCaptionGroup captionText= "selectOneChoice component with actionListener based on button workaround " partialTriggers="lgSelect"> <face:fieldSelect id="lgSelect" model="#{localeSelector. localeString}" label="lang" rendered= "#{not facesContext.application.defaultLocale.displayLanguage. equals(localeSelector.locale.displayLanguage)}"> <f:selectItems value="#{localeSelector.supportedLocales}" /> </face:fieldSelect></tr:panelCaptionGroup>

Now, if we try it again the resulting screen looks the way we expected it to be. The following screenshot shows how using the parent component's partialTriggers makes PPR works with the rendered attribute:

Page 95: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Rendering Pages Partially

[ 82 ]

The oneSelectChoice component disappears from our view when we select the language to be the same as the default language. In case, we change the language to another than the default one, for example, by setting this up in the browser, the selectOneChoice component appears as expected. When another than the default language is selected the selectOneChoice component appears, as shown in the following screenshot:

Finally, there is the application of PPR from the Java side by using Trinidad's RequestContext object, that we will inspect in the upcoming section.

Java-side PPR using Trinidad's RequestContextTrinidad's Java API is, as far as PPR is concerned, centered on one object called RequestContext that can be found in the context package, for example, org.apache.myfaces.trinidad.context. Although its name might appear to be somewhat misleading (there is no actual direct dependency on the web request scope), it really has its focus on the HTTP-basic per-request activity. Which, after all, any JSF application may be broken down to, so it provides all the functionality involved with the JSF support characteristic for the Trinidad framework. Thus, the following framework support methods are available:

Help support; for instance the methods getHelpSystem, getHelpTopic, and so onFile upload support; for example, getUploadedFileProcessorTrinidad dialog framework support; for example, launchDialog, returnFromDialog, getDialogService, and so onpageFlowScope support; getPageFlowScope returns the current pageFlowScope depending on which browser window and/or Trinidad dialog is open

Page 96: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 4

[ 83 ]

Skinning support, for example, getSkinFamilyFormatting support, for example, getFormattingLocale, getDecimalSeparator, and so onPPR support

PPR support is given with the help of the following functionality:

addPartialTarget(UIComponent newTarget): It lets newTarget become refreshed provided that component has a proper id set up—as described in the preceding section—otherwise functionality cannot be guaranteedaddPartialTargets(UIComponent component, String... relativeTarget): It allows to refresh several components given as Ids (relativeTarget) that must be relatively located to the componentgetPartialTargets(UIComponent component): It returns the partial targets of the passed componentaddPartialTriggerListeners(UIComponent listener, String[] trigger): It allows the passed listener to become refreshed by PPR if one or several of the components identified by an ID given in the trigger parameters is refreshed by PPR toopartialUpdateNotify(UIComponent updated): It allows to have all the components that listen on the passed component to be refreshed in the following JSF render phase

Usually, the most frequently used functionalities are addPartialTarget and addPartialTargets, which make sense in situations where the areas to be refreshed are found out no sooner than at runtime. Then sometimes in practice, it is interesting to test or workaround in case of a tag-based PPR difficulty and check if this Java-side approach works.

Application of PPR from the Java-sideLet us have a look at how to use PPR to refresh a panel area from a tree, which is a classic situation for the use of PPR from the Java-side. It is accomplished in the following two steps:

Page 97: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Rendering Pages Partially

[ 84 ]

Step I: Define the PPR sourceThe tag where the Java-side PPR is started from is, regarding efficiency, best setup with partialSubmit="true" as in the end it is a PPR that takes place and not a refresh of an entire page:

<tr:commandLink text="#{node.label}" actionListener="#{controllerTree.navigate}" part�alSubm�t="true">

The text attribute contains the respective tree node where a user click leads to an ActionEvent that is handled by the given navigate actionListener method from the controllerTree component.

Note that we do not use an ID here on purpose because this commandLink is a tree child. This means that it is used as part of the tree's dynamic process to render a tree menu structure, which we will see in Chapter 8, Growing a Tree.

Step II: Add the partial targetIn the navigate method of the declared actionListener, we can add the partial target as follows:

public void navigate(ActionEvent event) {... RequestContext.getCurrentInstance().addPartialTarget( FacesContext().getCurrentInstance.getViewRoot().findComponent( CommonID.componentAccordion));...}

Therefore, addPartialTarget is carried out on the CommonId.componentAccordion which is the panelAccordion component that keeps and organizes the panels, something we will further look into in Chapter 6, Building a Panel-based Content. To find this component, JSF's UIViewRoot method findComponent is applied. The following screenshot shows that a user click on a tree node carries out a PPR(Ajax) from the Java side:

Page 98: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 4

[ 85 ]

As an afterword, putting in contrast the various ways one can deal in Trinidad with partial page refreshing, it should be noted that in the majority of all day-to-day use cases, the purely tag-based PPR is the easiest and yet most effective way. Using PPR from the Java side is appropriate where dynamic page generation does not allow a tag-based PPR. Another observation is that, although the use of PPR from the Java side is not so pervasive, its application may result in becoming a basic mechanism for the workings of an entire JSF application. So quantitatively speaking, PPR from the Java side may be low in its Java code occurrence, but it will probably appear in the essential parts of the application, for example, providing the basic refresh mechanism for panel areas which can be seen in the demo application available on the Packt web site for this book.

Yet a further alternative is Trinidad's JavaScript alternative. However, the use of JavaScript is arguably good design and the philosophy is to keep it at a minimum as well as any other client-side techniques. Nevertheless, Trinidad has a lot to offer in this area and best practices have to be developed and introduced to profit from client-side techniques in an effective, controlled, and systematic way.

SummaryWe have seen Trinidad's framework technology, partial page rendering (PPR), to refresh parts of a page. Hereby, PPR has been inspected from two perspectives:

First, we had a thorough look at the main usage of PPR, tag-based partial rendering, and its application of the usual Trinidad framework attributes partialSubmit, autoSubmit, and partialTriggers. We saw how to identify the trigger to cause the partial page refresh and we have seen the aspects to consider to make sure the requirements for a proper working PPR are fulfilled. We also applied server-side caching of the model using the pageFlowScope, Trinidad's own session-scope based context.

Furthermore, we saw several cases of PPR usage: reflexive PPR in which a component refreshes itself, the limitations of PPR with value change event handling and PPR with the rendered attribute and in both cases how to overcome them.

Finally, we changed our perspective and saw how it is possible to work with PPR from the Java side using RequestContext , Trinidad's own context object. We had a look at a typical example where a tree is used as a menu structure from which panels are refreshed depending on the selected menu item.

Page 99: Apache Myfaces Trinidad 1.2 A Practical Guide (November
Page 100: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Web Application GroundworkThis chapter consists of developing 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 revisit 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 chapter we deal with deployment using Seam-gen to rapidly deploy at each change of any file.

Note that, the free code download available at the Packt web site will include all the required sources, tools or plugins, and the sample project setup discussed here.

NavigationNavigation 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:linkSupport of movement invocation through mouse-clicks on buttons or keyboard shortcuts on such controls, for example, tr:commandButton, s:button, and s:linkSupport of movement invocation through mouse-clicks on hyper links or keyboard shortcuts on such links, for example, tr:commandLink, and s:link

Page 101: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Web Application Groundwork

[ 88 ]

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 onFurther 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 that is going to be discussed in further detail in Chapter 12, Dialogs—Pop Up Your Web Application!. 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.

Page 102: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 5

[ 89 ]

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" act�onL�stener="#{controller.doLog�n}"

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" log�n-v�ew-�d="/log�n.xhtml">

... <exception class="org.jboss.seam.security.NotLoggedInException"> <red�rect v�ew-�d="/log�n.xhtml">

<message>Please log in first</message> </redirect> </exception>

Page 103: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Web Application Groundwork

[ 90 ]

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 FrameworkThe 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 in this book and concentrate on the purely programmatic side. For the declarative, please refer to http://myfaces.apache.org/trinidad/devguide/dialogs.html.

Page 104: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 5

[ 91 ]

Programmatically creating a dialogTo 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 sectionA 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 windowThe 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.launchD�alog(d�alog,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 dialogThere are two alternatives to pass objects to a dialog and back:

Using Trinidad's page flow scopeUsing Seam's scopes

Page 105: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Web Application Groundwork

[ 92 ]

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 book we take advantage of page flow scopes as Trinidad is in the foreground.

Returning from a dialogOnce 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 returnFromDialogpublic 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.

Page 106: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 5

[ 93 ]

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

AuthorizationWe complete the authorization outlined in Chapter 1, Introducing Trinidad, 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 as already described in the beginning. Let us briefly review these tasks.

Equipping each XHTML with authorizationAs 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> <restr�ct>hasR�ghtAccess</restr�ct>

</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.

Page 107: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Web Application Groundwork

[ 94 ]

User authorizationNow, 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 ;) SampleIdent�ty sampleIdent�ty = (SampleIdent�ty) �dent�ty;

�f (sampleIdent�ty.getUsername().equals("Dav�dThomas") &&

sampleIdent�ty.getPassword().equals("Tr�n�dad"))

{

sampleIdent�ty.addRole(SampleIdent�ty.roleEd�tor);

return true;

}

else �f (sampleIdent�ty.getUsername().startsW�th("anonym")

{

sampleIdent�ty.addRole(SampleIdent�ty.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.

Page 108: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 5

[ 95 ]

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 as seen in Chapter 2, Structuring and Building Pages with Facelets. We briefly sum up the approaches for both cases in the upcoming topics.

I18n on single labelsThis 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:�nputText columns="3" label="#{messages['teaUn�t.teaUn�ts']}"

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 componentsAgain, 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">

Page 109: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Web Application Groundwork

[ 96 ]

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.

PollingWe 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 �d="poller" pollL�stener="#{nav�.refreshSess�on}" �nterval="3000" />

The poll tag declaration must fulfill the following two requirements:

It must occur inside a form component, otherwise it is automatically disabled by TrinidadIt 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 listenerinterval: 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 {

Page 110: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 5

[ 97 ]

... /** * 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:

0�:1�:33,��0 INFO[controller] poller called at INVOKE_APPLICATION � �nt. 3000

0�:1�:3�,��� INFO[controller] poller called at INVOKE_APPLICATION � �nt. 3000

0�:1�:�0,��� INFO[controller] poller called at INVOKE_APPLICATION � �nt. 3000

0�:1�:��,00� INFO[controller] poller called at INVOKE_APPLICATION � �nt. 3000

Setting up the application with Seam-genIn 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

Page 111: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Web Application Groundwork

[ 98 ]

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:

h�bernate.connect�on.password=

workspace.home=java/ecl�pse/workspace/seamTestProject

model.package=com.test.Seam�dadAppl�cat�on

dr�ver.jar=../l�b/hsqldb.jar

act�on.package=com.test.Tr�n�dadSeam�dadAppl�cat�on

test.package=com.test.Tr�n�dadSeam�dadAppl�cat�on.test

database.type=

r�chfaces.sk�n=

h�bernate.default_catalog.null=

h�bernate.default_schema.null=

database.drop=n

project.name=Seam�dadAppl�cat�on

h�bernate.connect�on.username=

h�bernate.connect�on.dr�ver_class=

h�bernate.cache.prov�der_class=

project.type=war

�cefaces.home=

database.ex�sts=n

jboss.home=seamTestJBossHome

h�bernate.d�alect=

h�bernate.connect�on.url=

�cefaces=n

Page 112: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 5

[ 99 ]

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 book, 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-genAfter 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....

Page 113: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Web Application Groundwork

[ 100 ]

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.

Page 114: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 5

[ 101 ]

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.

DeploymentDeployment is very easy because with Seam-gen, we also inherit the deployment mechanism (already run during the project setup, earlier) provided by the Ant build process of Seam-gen. However, a few notes regarding the specific deployment of a Trinidad and Facelet web application in contrast with Seam-gen are discussed in more detail in the upcoming topics. The following screenshot shows the referenced libraries within the Eclipse IDE:

Page 115: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Web Application Groundwork

[ 102 ]

Trinidad-specific and Facelet-related changes to the project filesFirst of all, the lib directory lacks the Trinidad JAR files and the Facelet JAR:

jsf-facelets-1.1.14.jar

trinidad-api-1.2.9.jar

trinidad-impl-1.2.9.jar

So above JAR files must be added to the lib directory while others, such as the RichFaces JARs, should be removed as we want to achieve a clean setup of a single component library. A mix-up should be avoided to keep away from integration problems. The following screenshot shows the contents of the lib directory inside Eclipse (part I only shows files not referenced by the Eclipse project):

Page 116: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 5

[ 103 ]

Most importantly, we need to update the file deployed-jars.list, as it is looked at by the build process to provide the application server with the required JAR files. So we reduce this list file to a more minimal Trinidad-specific version:

antlr-runtime.jar

commons-beanutils.jar

commons-digester.jar

core.jar

drools-compiler.jar

drools-core.jar

janino.jar

jboss-el.jar

jboss-seam.jar

jboss-seam-*.jar

jbpm-jpdl.jar

jsf-facelets-1.1.14.jar

mvel14.jar

trinidad-api-1.2.10.jar

trinidad-impl-1.2.10.jar

The following screenshot shows the contents of the lib directory inside Eclipse (part II only shows files not referenced by the Eclipse project):

Page 117: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Web Application Groundwork

[ 104 ]

Next, in the resources directory we must add a provider for Seam's conversation mechanism to support Seam conversations in Trinidad dialogs. Its file name must follow the Trinidad naming convention for this provider type, and it must be located below resources in META-INF/services:

File name: org.apache.myfaces.trinidad.PageFlowScopeProviderContents: It must contain the name and package path of the provider class, for example, trinidad.SeamPageFlowScopeProviderImpl

This class is created as an implementation of Trinidad's abstract class PageFlowScopeProvider that can be easily done with Eclipse's comfortable class creation wizard. In the final chapter of this book we will deal more extensively with dialogs.

There are further simplifications:

The org.jboss.seam.ui.richfaces package in the resources directory is required for Seam's support of RichFaces, but is obsolete for us and should thus be deletedIn the WEB-INF directory, we can carry out the following activities:

We can add a folder for Facelet composition componentsWe can simplify the components.xml file by getting rid of persistence declarations such as persistence:managed-persistence-context, persistence:entity-manager-factory, and drools:rule-base declarations (the security we only leave is the one for the identity object)The faces-config must be adapted to suit the Trinidad renderer as described earlierThe pages.xml becomes even simpler as we practically avoid it altogether using the dialog framework as described in the navigation section earlierWe must modify the web.xml to suit Trinidad's requirements (see configuration in the upcoming chapters)

°

°

°

°

°

Page 118: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 5

[ 105 ]

We must add three additional files, namely the trinidad-config.xml, the trinidad-skins.xml, and a taglib.xml to declare the Facelet composition componentsThe *-dev-ds.xml and *-prod-ds.xml files may be emptied of any specific data because no database-backing is used in our test project

Trinidad-specific changes to the Ant build scriptThe build.xml in the project root must only be slightly adapted as follows:

The war target must be extended to also copy the PageFlowScopeProivder class, that is:

<copy tofile="${war.dir}/WEB-INF/classes/META-INF/services/ org.apache.myfaces.trinidad.context.PageFlowScopeProvider" file="${basedir}/resources/META-INF/services/ org.apache.myfaces.trinidad.context.PageFlowScopeProvider" overwrite="true" />

Furthermore, this target needs an addition to cover the Facelet components, that is:

<copy todir="${war.dir}/WEB-INF"> <fileset dir="${basedir}/resources/WEB-INF"> <include name="lib/*.*"/> <include name="faceletComponents/*.*"/> <include name="classes/**/*.class"/> </fileset> </copy>

°

°

Page 119: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Web Application Groundwork

[ 106 ]

Deployment from EclipseNow, deployment is child's play. After you have configured the application server path in the build.properties file, updated its only property jboss.home to your local JBOSS installation (for example jboss.home =/Applications/JBoss/jboss-4.2.2.GA), and set up Eclipse to use JBOSS as application server, carry out the following steps:

1. Choose the Server view, and then click on New | Server, as shown in the following screenshot:

Page 120: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 5

[ 107 ]

2. Select JBoss v.4.2 (Seam is specified to work with 4.2), as shown in the following screenshot:

Page 121: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Web Application Groundwork

[ 108 ]

3. Leave the configured projects in the Add and Remove Projects dialog empty, as the project is deployed by the Seam-gen Ant build. Click on Finish.

Any change to any project file causes the Ant build process to be rerun. This also includes a deployment to the JBoss application server in its final step.

Of course, it is always possible to switch off the automated build and deploy, particularly in cases where the applied machine has not enough performance. However, because of the thinness of the sample project, this should not be necessary (even on an IBook G4 the JBoss starts up in a minute).

Page 122: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 5

[ 109 ]

Browser client setupAs a browser, I recommend Firefox 2 or Firefox 3. The latter version still has a few compatibility issues, but they should soon be resolved. Furthermore, there are a few subtle configuration issues to take care of that are stated as follows:

From my past experience, I have seen that Seam and Trinidad work well when Cookies are disabled because when we take a server-side approach, this is not an issue. Remember that both Trinidad and Seam support client-side techniques; however, this is not an area that this book aims to cover.Versions of Firefox below 2.0.0.17 should be avoided because of security and memory management issues. The following screenshot shows how Firefox's Privacy preferences tab allows setting up exceptions for cookies.

Page 123: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Web Application Groundwork

[ 110 ]

Disabled cookies make sure that that session and conversation management is properly handled, and that a unique session ID is assigned for each session that the user opens. This is not critical for thumbing through this book's web sample application, but would be important to consider for real-life applications. The following screenshot shows the event of clicking on disable to set up disabled cookies for a Seam or Trinidad web application on the your_server host:

Last but not least, when it comes to Trinidad skinning, setting the very practical web.xml parameter switch to true only works with disabled cookies which, in terms of effective work, is crucial while the skin is being developed:

<context-param> <param-name> org.apache.myfaces.trinidad.CHECK_FILE_MODIFICATION </param-name> <param-value> true </param-value> </context-param>

Page 124: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 5

[ 111 ]

The following screenshot shows how to set up disabled cookies for a Seam or Trinidad web application on the your_server host:

1

SummaryIn this chapter, we have seen the basic parts of the web sample application that serves as Trinidad—for example, login registration, user authorization, navigation, internationalization, and polling—have been revisited and discussed with occasional refinement where required.

Login and authorization are based on Seam's security framework. It allows using an identity object that keeps the user's credentials that result from her or his login to the application through login page supported by Seam.

In connection with navigation, we took a look at the Trinidad dialog frameworks that are used in the sample application to navigate with a minimum declaration effort for each page because the dialog framework allows a purely programmatic approach of dialog creation, usage, and closure.

Internationalization is implemented by the application of the Seam messages object. It is applied in two ways. First, all Facelet composition components are equipped with JSTL logic that looks up the respective messages properties file according to the provided label and ID of the respective component. Second, the messages object is directly used for any other components that are not encapsulated as composition components.

Page 125: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Web Application Groundwork

[ 112 ]

Polling is used by means of the Trinidad poll component to keep the user session alive unless the browser, or the page of the sample application is closed. The poll component supports a PollEvent listener that allows to easily implementing such functionality. This keeps the code short and maintainable.

Furthermore, we discussed the generation of the sample application by means of Seam-gen—an application generator specialized on the provision of a startup project. It has a built-in Seam configuration that allows rapid deployment at each change of any file.

Page 126: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a Panel-based Content

This chapter deals with Trinidad's panelAccordion and showDetailItem components to show how they can be combined to build a panel-based, panel-wise collapsible content.

We will see how the components interact with each other and how to achieve the desired refresh behavior. Moreover, we will get a clear idea of how nicely Facelets and Trinidad work together to produce an effective panel-based layout for the entire application. We shall be covering the following topics in this chapter:

How Trinidad's panel components work together How to define a panel-based layout template How to create a minimal panel modelHow to define a skin for the panel-based layout

Where the Trinidad panel components live and what they supportThe involved components all stem from the org.apache.myfaces.trinidad.component.core.layout package, which contains a series of panel-specific components that are related to each other, often in a parent-child relation. The panelAccordion and showDetailItem are exactly an example for such a relation. Together, when appropriately setup, they result in an effective combination that allows building a panel-based web application.

Page 127: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a Panel-based Content

[ 114 ]

Our sample web application is going to deal with the presentation of the main features and components of the Apache MyFaces Trinidad framework. We will develop a basic navigation and page structure that allows easy navigation and visualization the contents. However, the following typical issues need to be taken into consideration:

Offer a navigation typical of today's web applications—that is, we will offer a tree navigation on the left-hand side (presented in Chapter 7, Building a Form) to navigate across the component demonstrations of each chapterDefine a header area that displays an orientation (title and path) of the current viewDivide the content area into a section that displays the respective component, and a section that displays a description of the component and its demonstrated features; one of both areas may be closed in a favor of more space for the other

The last issue is the one we are going to deal with by the use of the aforementioned panelAccordion and showDetailItem components. Therefore, let us first take a look into these components and then apply them in conjunction to solve our issue. The following image shows the typical structure of a web application's UI (navigation, header, and content—with panels—are the usual areas to work out):

Page 128: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 6

[ 115 ]

The accordion and showDetailItem componentsBoth, accordion and showDetailItem components are an example for a recurring Trinidad principle that is typical of component frameworks—components that are designed to work together and effectively interact with each other. So the accordion takes care of the general overall behavior of its parts, while the showDetailItem component is designed as such a part but with additional specific behavior.

Let us take a look at each of these components.

How to play the panelAccordionThe main attributes of tr:panelAccordion focus on the disclosure of its parts, that is, its JSF children components:

The discloseMany attribute, if true, allows the accordion to keep several, or even all, children (in our case showDetailItem panels) disclosed; otherwise, only one child at most is disclosableThe discloseNone attribute, if true, allows all the children to be closed (collapsed); otherwise, there must always be one disclosed child

We will use discloseMany="true" and discloseNone="false" so that at least either the description, or the content area, is always disclosed resulting in three possible closure or disclosure variations of panel display. The following screenshot shows the first method of the closure and disclosure variation setup with discloseMany="true" and discloseNone="false":

Page 129: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a Panel-based Content

[ 116 ]

So the user clicks on a panel heading of an open panel and it is closed, while the other always remains open. The effect of this panel behavior is that a fuller view of a certain panel may be gained by allowing it to occupy the space of those panels that are minimized by the user. The following screenshot shows the second method of closure and disclosure variation setup with discloseMany="true" and discloseNone="false":

As for the other attributes, there are only those left that are also common to many other Trinidad tags. The one common attribute that we are going to take advantage of is the partialTriggers attribute because we only want to refresh the accordion and its parts while the rest of the page may remain the same. The following screenshot shows the third method of closure and disclosure variation setup with discloseMany="true" and discloseNone="false":

The showDetailItem component—press to play an accordion keyTo implement the two panels for the content and description area, we take advantage of the showDetailItem component.

The main attribute to control its display is simply the Boolean disclosed, that we use to setup the initial display of the two panels, the description area being displayed from the start and the content initially set to disclosed="false".

Page 130: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 6

[ 117 ]

Another special feature of this component is its toolbar facet. Its purpose is to offer the user a panel compartment (located on the panel header) that allows adding navigation and/or controlling components that do something with this component's content. For example, we could use this toolbar to place a command button that when clicked, displays an even fuller view of the panel by showing its contents on a full main browser page. We will see how this is done in the code of the upcoming section.

Regarding the other attributes, Trinidad's framework character is once again striking. In fact, all of the other attributes are typical standard Trinidad tag attributes. Therefore, the Trinidad framework stresses keyboard support, which we can clearly see here as well. As with the accessKey and the textAndAccessKey attributes we can provide a short cut keyboard command for each showDetailItem.

As an aside, note that the control keys to use keyboard shortcuts vary from browser to browser, and even from client to client. For instance, on a Mac, keyboard shortcuts on a Firefox are affected by using the combination of three keys: the function key (fn), control key, and the key for the respective letter, whereas on a Windows Firefox, the combination of the Alt and Shift keys are used (again along with the key for the respective letter, of course).

The PanelModel component—a simple and effective POJOAs for the model side, in simple cases, it is not usually required to keep a model of the panel on the server side. However, because we want to manipulate the panels in a concise and object-oriented way using PPR, we need to reference them as objects. So we achieve an efficient manipulation of their attributes without having to struggle with a series of global parameters. It suffices to define the following PanelModel, a simple yet effective POJO (Plain Old Java Object):

public class PanelModel{ private String include; private String label; private boolean rendered; private boolean opened;

So we are able to manipulate the following main attributes of a panel:

The include attribute to hold the include file of the panel, that is the actual panel contentsThe label attribute contains the header title of the panelThe rendered attribute is true if, and only if, the panel is renderedThe opened attribute is true if, and only if, the panel is opened

Page 131: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a Panel-based Content

[ 118 ]

We generate an instance of a panel that is made of an empty content, and an empty label. It is initially open and rendered:

public PanelModel() { super(); // initially requires an empty include file otherwise // Facelets gets into a stack overflow.. th�s.�nclude = "layout/empty";

// initially no label this.label = ""; // initially rendered and opened this.opened = true; this.rendered = true; }

It is important to get a panel model that comes with a reference to an empty include file. Therefore, if it is shown without another include file that actually has a non-empty content, Facelets does not get confused and tries endlessly to find a content which would end in a stack overflow.

The rest of this object's class is simply all the expected setters and getters:

/** * @return is the panel rendered? */ public boolean isRendered() { return rendered; }

/** * @param rendered true if the panel is rendered */ public void setRendered(boolean rendered) { this.rendered = rendered; }

/** * @return is the panel open? */ public boolean isOpened() { return opened; }

Page 132: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 6

[ 119 ]

/** * @param opened true if the panel is open */ public void setOpened(boolean opened) { this.opened = opened; }

/** * @return the include file of the panel i.e. the actual panel contents */ public String getInclude() { return include; }

/**

* @param include the include file of the panel i.e. the actual panel contents */ public void setInclude(String include) { this.include = include; }

/** * @return the label i.e. the header title of the panel */ public String getLabel() { return label; }

/** * @param label the header title of the panel */ public void setLabel(String label) { this.label = label; }

}

Page 133: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a Panel-based Content

[ 120 ]

The combination of Accordion and showDetailItemNow, when we put it all together the main part of the layout results as follows:

<tr:panelAccordion id="packtAccordion" discloseMany="true" discloseNone="false">

As expected, we have started by declaring our panelAccordion with discloseMany and discloseNone.

The partial trigger will actually be the respective tree node, a dynamically added child item, which is why we do not declare a (static) partialTriggers here. We will later see (in Chapter 8, Growing a Tree) how to affect a more dynamic partial rendering programmatically through Trinidad's PPR API, which has already been explained in theory in the first part of this book. The following image shows the envisioned dynamic behavior, where a tree node is clicked and the panels are setup and refreshed accordingly:

Next, follow the parts of the panel:

<tr:showDetailItem id="panelDescriptionArea" accessKey="d" text="#{empty controllerPanel.descr�pt�onPanel.label? 'Descr�pt�on':

controllerPanel.descr�pt�onPanel.label}"

Page 134: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 6

[ 121 ]

rendered="#{empty controllerPanel.descr�pt�onPanel.rendered ? true :

controllerPanel.descr�pt�onPanel.rendered}"

d�sclosed="#{empty controllerPanel.descr�pt�onPanel.opened ? true :

controllerPanel.descr�pt�onPanel.opened}">

<f:facet name="toolbar">

<tr:commandButton styleClass="panelTool" icon="img/dtpick.gif" action="showFullViewDescription"/> </f:facet> <tr:subform id="formDescription"> <ui:include src="../#{controllerPanel.descr�pt�onPanel.�nclude}.xhtml" />

</tr:subform></tr:showDetailItem>

So we decide the first showDetailItem to be our description area whose appearance as the first panel probably makes, intuitively speaking, more sense than the other way round—but, of course, this is arbitrary.

In the preceding piece of code, we can see how to access each of the attributes of the description panel. If no label is given, we revert to a standard label; otherwise, we access the panel model's label. If we have information on the panel model side as to whether or not the rendering is to be done, we decide this according to that attribute; otherwise, we revert to the default of rendering it. Finally, we access the panel model's opened attribute to find out if the panel is to be shown in a disclosed state, assuming in the same way a default of opened. The following screenshot shows a basic welcome using the description panel at startup:

Page 135: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a Panel-based Content

[ 122 ]

An alternative to pure FaceletsAlternatively, without a model, there would have been various Facelet parameters used to setup the panels now; for instance:

panelDescriptionAreaTitle to define the title of the description panelpanelDescriptionAreaRendered to define if the description panel is renderedpanelDescriptionAreaOpen to define if the description panel is disclosedpanelDescriptionAreaInsert to insert a panel content by this name which would be the specific content of the respective Trinidad component to be demonstrated

This way, the developer would have overwritten their behavior by setting them to other values by means of ui:param. For instance, regarding the description panel, the layout template would be simpler and look like:

<tr:showDetailItem id="panelDescriptionAreaTitleId" text="#{panelDescriptionAreaTitle}" rendered="#{panelDescriptionAreaRendered == null ? true : panelDescriptionAreaRendered}" disclosed="#{panelDescriptionAreaOpen == null ? True : panelDescriptionAreaAreaOpen}">...

Whereas, a template client would apply the respective Facelets parameters, as follows:

<ui:composition template="/WEB-INF/layout/template.xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:trh="http://myfaces.apache.org/trinidad/html" xmlns:tr="http://myfaces.apache.org/trinidad">

<ui:param name="panelDescriptionAreaTitle" value="#{messages['descTitle']}" /> <ui:param name="panelDescriptionArea" value="panelSpecificAreaContent.xhtml"> <ui:param name="panelDescriptionAreaAreaOpen" value="false" />

</ui:composition>

The alternative approach is fairly straightforward.

Page 136: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 6

[ 123 ]

However, with growing demands as to PPR behavior, ease and transparency of manipulation, applying our simple POJO-type panel models makes it all easier to handle. In particular, there is a transparent access of their attributes that is practically the same, no matter if we do this from the pure Java API server side or the page XHTML side using EL expressions.

Therefore, in above code, we prefer our model-based approach—where we use EL expressions that reference the panel model object's attributes:

controllerPanel.descriptionPanel.label to define the title of the description panelcontrollerPanel.descriptionPanel.rendered to define if the description panel is renderedcontrollerPanel.descriptionPanel.opened to define if the description panel is disclosed; if this parameter is not given, the default of disclosure is assumedcontrollerPanel.descriptionPanel.include to fill a panel content with its provided include file source that will be the specific description of the respective Trinidad component to be demonstrated

The content panel—same soul, different incarnationThe second panel is an instance of the same model and thus handled analogously. Only the respective property names are slightly different, but analogously recognizable (controllerPanel.contentPanel.label, controllerPanel.contentPanel.rendered, and so on):

<tr:showDetailItem id="panelContentArea" text="#{empty controllerPanel.contentPanel? 'Content':controllerPanel.contentPanel.label}" rendered="#{empty controllerPanel.contentPanel.rendered ? true : controllerPanel.contentPanel.rendered}" d�sclosed="#{empty controllerPanel.contentPanel.opened ? true : controllerPanel.contentPanel.opened}"> <f:facet name="toolbar"> <tr:commandButton styleClass="panelTool" icon="img/dtpick. gif" action="showFullViewContent"/> </f:facet> <u�:�nclude src="/#{controllerPanel.contentPanel.�nclude}. xhtml" /> </tr:showDetailItem>

Page 137: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a Panel-based Content

[ 124 ]

Because our pages will all have the same double panel structure, both panels are now the combined replacement for the earlier <ui:insert/> in the early Facelets chapter version of the layout.xhtml.

Both panels are accessed through a new component that acts as kind of a wrapper, possibly equipped with controller behavior. This way, we already take care of future demands. It is probable that we will sooner or later need to add code for further powerful controls of the panels. Thus, the location where we would add this is already prepared. Let us take a look at this to clear up some interesting details.

ControllerPanel keeps the panels under the same roofThe ControllerPanel is a dedicated controller component that manages the panels, which allows keeping runtime changes of the panel contents and states separate from any other controller component. A tree controller would then access the ControllerPanel if it wanted to do anything with the panels. We define the ControllerPanel to be a Seam Session component available at startup time:

@Name("controllerPanel")@Startup@Scope(ScopeType.SESSION)public class ControllerPanel {

private PanelModel contentPanel; private PanelModel descriptionPanel;

public ControllerPanel() { super(); setContentPanel(new PanelModel()); setDescriptionPanel(new PanelModel()); }

Therefore, our ControllerPanel is already in the session context at startup time loaded with two empty panels that wait to be filled.

We can also declare it as a Seam conversation component that would stress the content that is kept to be dependent of the current main conversation. This would make sense in real applications that work a lot with operative and transactional data.

Page 138: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 6

[ 125 ]

The rest of this controller shows that it is not much more than a wrapper of the panels, as follows:

public PanelModel getContentPanel() { return contentPanel; }

public void setContentPanel(PanelModel contentPanel) { this.contentPanel = contentPanel; }

public PanelModel getDescriptionPanel() { return descriptionPanel; }

public void setDescriptionPanel(PanelModel descriptionPanel) { this.descriptionPanel = descriptionPanel; }

}

However, this simple wrapper character is subject to change as soon as further requirements arise for the panel management. An example for such a requirement would be the visualization of parent-child data that could be distributed across two panels and thus, would require a synchronized management of both.

The toolbar facetThe toolbar facet is a part of each showDetailItem and is used to implement the full view of each panel as a main browser page. For better clarity, here is the relevant part of each showDetailItem:

<f:facet name="toolbar">

<tr:commandButton styleClass="panelTool" icon="img/dtpick.gif" act�on="showFullV�ewDescr�pt�on"/>

</f:facet>

To this end, we apply the preceding Trinidad command button as a JSF child of the toolbar facet. When clicked, the following Seam pages action called showFullViewDescription is invoked (from the pages.xml):

<nav�gat�on from-act�on="showFullV�ewDescr�pt�on">

<redirect view-id="/fullViewDescription.xhtml" /> </navigation>

Page 139: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a Panel-based Content

[ 126 ]

The fullViewDescription.xhtml is simply based on a layout template that is a reduced version of the main template that just references the actual content of the respective panel:

<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:s="http://jboss.com/products/seam/taglib" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:tr="http://myfaces.apache.org/trinidad" xmlns:trh="http://myfaces.apache.org/ trinidad/html" xmlns:face="http://www.packt.com/facelets" xmlns:c="http://java.sun.com/jstl/core" template="layout/templateDescr�pt�onFullV�ew. xhtml"/>

Therefore, for the description panel templateDescriptionFullView.xhtml, the reduced main template looks like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><trh:html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:tr="http://myfaces.apache.org/trinidad" xmlns:trh="http://myfaces.apache.org/trinidad/html" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:c="http://java.sun.com/jstl/core" xmlns:s="http://jboss.com/products/seam/taglib" xmlns:face="http://www.packt.com/facelets"> <trh:head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>TestProject</title> <link href="stylesheet/theme.css" rel="stylesheet" type="text/ css" /> </trh:head>

<trh:body> <div class="body"> <tr:form id="formBase"> <div id="center"> [...] <tr:messages globalOnly="true" styleClass="message"/>

Page 140: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 6

[ 127 ]

<tr:subform id="formDescription"> <ui:include src="../#{controllerPanel.descriptionPanel. include}.xhtml" /> </tr:subform> </div> </tr:form> </div> <div class="footer"> ... </div> </trh:body></trh:html>

The reduced layout template for the content panel is practically identical, except for the name of the subform and includes reference of the panel.

A little Facelet optimization is possible here because we could generalize a further template from these two highly similar templates.

We can make use of the panels' toolbars to include a full view function of each panel; the following screenshot shows the welcome panel:

Page 141: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a Panel-based Content

[ 128 ]

Skinning the panelsAt this point, despite the introductory character of this book, it makes sense to comment on a few aspects of the application-wide CSS-based skin definition of the components as their skinning is not as obvious as one might think. Instead, we will consider specific skinning issues as far as components are concerned. The following screenshot shows the welcome panel before any skinning is applied:

Skinning the Accordion and its childrenFirst of all, it makes sense to outline the panelAccordion which we can easily accomplish by addressing the component's Trinidad CSS class af|panelAccordion in the application-wide skin CSS file as follows:

af|panelAccordion { padding:7px; border:3px groove green; }

Next, by means of Trinidad's skinning selectors, we define width and margins for panelAccordion that is inherited by its children, that is, our showDetailItem components.

af|panelAccordion::content{ width:98%; margin-top:20px; margin-bottom:20px; }

Page 142: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 6

[ 129 ]

This is the first skinning selector that actually sets up the skin of its children. Therefore, the accordion's skinning sets up the skinning of its children and the children's particular skinning is confined to a narrower set of skin characteristics that are only pertinent to the specific showDetailItem child component as we can see in the next section.

The above setup of the content selector ensures that almost the entire horizontal space is used for the content area of each showDetailItem that is also separated from its border by the indicated margins. On the whole, we achieve a clear distinction between borders and content (of course, all this always depends on one's style guide and some people prefer a greedier space usage).

Furthermore, we setup headers of panelAccordion that means all of its children will inherit the same look:

af|panelAccordion::header-collapsed, af|panelAccordion::header-disabled, af|panelAccordion::header-expanded { background-color: pink; border:3px groove green; padding:7px; }

In particular, this allows the setup of each showDetailItem header, its background, border, and padding. The titles of panelAccordion, children included, are set up by using Trinidad's title* descriptors that allow the setup of the foreground color of the title of each showDetailItem:

af|panelAccordion::title-link, af|panelAccordion::title-disabled-link { font-size:10px; font-weight:bold; color:green; padding-left:12px; }

Page 143: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a Panel-based Content

[ 130 ]

Skinning specific properties of the Accordion's children Finally, we define the remaining skinning for the showDetailItem component. The only thing left is the assignment of icons for disclosure:

af|showDetail::disclosed-icon { content:url(/img/disclosed-icon.png); }

And closure:

af|showDetail::undisclosed-icon { content:url(/img/undisclosed-icon.png); }

The following screenshot shows the welcome panel after changing to the new skin definitions:

Switching the skins on configuration levelIn connection with our skinning, it is noteworthy to mention that changing skins in Trinidad is a straightforward task. For example, in this book's web application example there are two skins to be found which basically differ in their panel skin:

skin.css: It is the default skin with no specific panel skinningskinPink.css: It includes the panel skinning as presented in this chapter

Page 144: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 6

[ 131 ]

Now to switch from one skin to the next is very easy. The Trinidad configuration file trinidad-skins.xml must be provided in the WEB-INF folder with a reference to the specific skin CSS. In this book's web application example it looks as follows, which is quite a typical setup:

<skins xmlns="http://myfaces.apache.org/trinidad/skin"> <skin> <id>skintest.desktop</id> <family>skintest</family> <render-kit-id>org.apache.myfaces.trinidad.desktop</render-kit-id> <style-sheet-name>stylesheet/skin.css</style-sheet-name> <bundle-name>messages</bundle-name> </skin></skins>

Thus, we define a skin by setting up the following properties:

id: This is the unique name that identifies the skinfamily: This is used in the trinidad-config file to select the skin to be usedrender-kit-id: This is the ID of the render-kit to be used, which—for browser skins—is usually Trinidad's default render-kit 'org.apache.myfaces.trinidad.desktop'style-sheet-name: This is the actual skin CSS file, along with its path relative to web content folder. Thus, alternatively, one may select the skin by simply declaring another CSS herebundle-name: This is the message bundle

So there are actually two ways to switch the skin:

By declaring another skin CSS in the trinidad-skins.xmlBy declaring another skin family in the trinidad-config.xml

A brief look at the trinidad-config.xml of this book's web example application illustrates the latter approach:

<?xml version="1.0"?><trinidad-config xmlns="http://myfaces.apache.org/trinidad/config"> <!-- Enable debug output --> <debug-output>true</debug-output> <client-validation>DISABLED</client-validation> <sk�n-fam�ly>sk�ntest</sk�n-fam�ly>

<accessibility-mode>inaccessible</accessibility-mode> </trinidad-config>

Page 145: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a Panel-based Content

[ 132 ]

Therefore, by setting the skin by the use of the skin-family declaration, which is a required declaration in the trinidad-config.xml, we are able to select one of possibly several skins declared in the trinidad-skins.xml. Of course, a restart of the application server is required to change the skin this way.

SummaryIn this chapter, we have seen how to create a panel-based page content by means of the Trinidad panel components. In conjunction with Facelets, we have created an effective combination that enables the developer to use include files as panel content prepared to work with partial-page rendering to only refresh the panel area.

We have gained an insight into a typical relation between the Trinidad panel objects—the panel components we have applied stand in a parent-child relation, as an aspect that is also apparent in the skinning of these components.

We have made a comparison between a model-based approach and a pure Facelet-based approach that resulted in the preference of the model-based approach for the sake of effective, uniform and encapsulated component access.

Finally, we have taken a look at the skinning features of the Trinidad panels and observed that the parent skinning largely influences the children components so that only a few child-specific skinning features remain to be set.

Page 146: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a FormIn this chapter, we shall discuss how to combine Trinidad's tags and Facelet composition components to build the most flexible and well-formatted forms that include messaging support. With Trinidad's formatting features in particular, building forms that suffice professional web application requirements is finally a straightforward task. The following topics will be covered in this chapter:

InternationalizationGood formattingMessaging supportConverter-based passing of validated input form dataPassing forms independently of other forms and nesting forms within forms to manage areas of validationThe ease of developing forms by using specialized, Facelet-based components

For internationalization, we profit from the simple and effective access provided by Seam and Facelets as pointed out in the beginning (under the section Facelet composition components, in Chapter 2, Structuring and Building Pages with Facelets) that is, we use messages[msg] in combination with JSTL encapsulated in Facelet composition components.

To achieve good formatting, we take advantage of Trinidad's panelFormLayout component that allows an automated alignment of Trinidad and JSF input components. This also ensures internationalization because the automated alignment is done for each language (which also means that the layout has to be cross-checked for each language).

As each Trinidad input component is equipped with messaging support (also simple JSF input components can be decorated by Trinidad with messaging support), it is child's play to use it.

Page 147: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a Form

[ 134 ]

To this end, Trinidad offers a couple of standard Trinidad tag attributes, such as required and showRequired, as well as a special decorator component called panelLabelAndMessage. All of which we have seen before in Chapter 2, Structuring and Building Pages with Facelets.

Moreover, by the use of JSF converters and validators built-in to Facelet composition components, the developer is enabled to always work with the right converter and validator according to the composition component he or she chooses. This means that we can build our own components according to the various types of input a user may possibly need, for example, dates, numbers (and herein sub types of numbers such as whole numbers, floating point numbers, and so on), and text.

By the means of Trinidad's subform component, we are able to choose which parts of a form are sent and which ones are omitted concerning validation. This includes such behavior as getting the last state of a part of a form for the pop-up of a dialog where a search is executed based on exactly that state.

An exception to this approach is recommended when only a single field is to be passed to such a pop-up. In this case, we should take advantage of JSF's classical immediate attribute to circumvent validation which is more straightforward to use, and more flexible when incorporated into other containers (such as the Trinidad table, for instance). As this is standard JSF, we will not digress into this area; we leave it by mentioning it here in favor of the focus on Trinidad subforms.

Finally, through the aforementioned pervasive use of Facelet composition, components on the input component level forms are built much faster than directly applying the component library's input objects. Thanks to the Facelet encapsulation that hides many repetitive details, (for example, a field-level help) the developer has much less typing effort and the pages become less cluttered with detail.

Building a formLet us now start building up a form that covers the mentioned criteria. We apply the following bottom-up approach:

1. Build the composition components to cover all the required input component types and their respective requirements they are supposed to fulfill (based on the findings on Facelets and their combination with JSTL).

2. Build the respective form by assembling concrete instances of composition components from the previous step into a panelFormLayout parent.

Page 148: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 7

[ 135 ]

3. Decorate the form with the required form send components, namely a form with nested subform components.

4. Add a general message area using tr:messages, Trinidad's standard component for this task.

This approach is quite versatile and could be applied in diverse Trinidad-based projects.

Step I: Building the composition componentsUsually, the following types of input are the ones to consider:

text input: A line of text may be typed in date input: A certain date with certain conditionals may be typed in number input: Inputs that covers rational (float) and whole (integer) numbers and that is further restricted by intervals and other excluding conditionsselection input: This is used to select one or several elements from a drop-down or at-once displayed list

Of course, there are more variations possible, for instance combinations of above types. However, this would be much too close to the respective project specifics to be covered here. Thus, we will limit our considerations to above types the upcoming topics.

The fieldText componentThe component named fieldText is the text input composition component. Let's have a look at how fieldText can be defined. It uses a built-in preprocessor that decorates each composition component that is defined and applied here (refer to the Facelet composition components section in Chapter 2, Structuring and Building Pages with Facelets).

<face:paramBu�lder>

<tr:inputText showRequired="true" label="#{msgLabel}" required="#{required}" rendered="#{rendered}" disabled="#{readOnly}" value="#{model.value}"

Page 149: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a Form

[ 136 ]

id="#{id}" maximumLength="#{maxLength}" labelStyle="#{labelStyle}; width:#{labelWidth};" contentStyle="#{contentStyle} margin-left:#{margin}px; width: #{width}px" shortDesc="#{shortDesc}" showRequired="true" columns="#{columns}" onchange="#{onChange}" autoSubmit="#{autoSubmit}" immediate="#{immediate}" secret="#{secret}"> <c:choose> <c:when test="#{(empty standardConverter and empty converter) or standardConverter==true}"> <f:converter converterId="faceConverterText" />

</c:when> <c:otherwise> <c:if test="#{not empty converter}"> <f:converter converterId="#{converter}" />

</c:if> </c:otherwise> </c:choose> <c:choose> <c:when test="#{(empty standardValidator and empty validator) or standardValidator==true}"> <f:val�dator val�datorId="faceVal�datorText" />

</c:when> <c:otherwise> <c:if test="#{not empty validator}"> <f:val�dator val�datorId="#{val�dator}" />

</c:if> </c:otherwise> </c:choose> <ui:insert/> </tr:inputText> </face:paramBu�lder>

We use a component decoration as described in the Facelet composition components section of Chapter 2, Structuring and Building Pages with Facelets. This ensures that certain values are properly setup, for example, the I18n messages.

Page 150: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 7

[ 137 ]

One of the main advantages to the use of Facelet composition is that we are able to provide standard conversion and validation while still allowing for deviations by the developer who may provide other validators or converters or may even need to work without any converter or validator at all. Thus, with a minimal use of Facelet parameterization we get a call such as,

<face:f�eldText �d="anId" model="#{aModel}" />

This function includes standard conversion and validation. Furthermore, we could go ahead and include standard help, for example, by using the Oracle Help for the Web that is supported by Trinidad. All this would be automatically provided just by typing the simple preceding function. The following screenshot shows a simple usage of the fieldText composition component:

The fieldDate component The fieldDate component is the date input composition component that profits from using Trinidad's inputDate component—notably by using it without the chooseDate component as this way is much simpler and more reliable. There is a bad tradition in component libraries to somehow support the brokenness of date input components:

<face:paramBu�lder>

<tr:inputDate id="#{id}" required="#{required}" disabled="#{readOnly}" rendered="#{rendered}" value="#{model.value}" columns="8" maximumLength="10"

Page 151: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a Form

[ 138 ]

contentStyle="#{contentStyle} width:#{width}" autoSubmit="#{autoSubmit}" immediate="#{immediate}" label="#{msgLabel}" shortDesc="#{shortDesc}"> <tr:convertDateT�me />

<c:choose> <c:when test="#{(empty standardValidator and empty validator) or standardValidator==true}"> <tr:validateDateRestriction invalidDaysOfWeek="Sat Sun"/> </c:when> <c:otherwise> <c:if test="#{not empty validator}"> <f:val�dator val�datorId="#{val�dator}" />

</c:if> </c:otherwise> </c:choose> <ui:insert /> </tr:inputDate></face:paramBu�lder>

A standard converter is provided that is supposed not to be replaced. Therefore, we do not provide any replacement or neutralization mechanism as done with the foregoing choose structures. The following screenshot shows a simple usage of the fieldDate composition component:

Page 152: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 7

[ 139 ]

The fieldNumber componentThis component is the number input composition component that distinguishes between integers and floating point numbers. To help with this, there is a parameter called type that is used as a discriminator between these two. If omitted, the component assumes the larger range of numbers. If no converter is passed, a standard converter is assumed as in the foregoing component. This standard converter is provided by the developer in a way that customizes Trinidad's existing number converter that allows avoiding undesired conversion behavior and overwrites it where required (which is covered in any general JSF). For validation, the procedure is simplified because we assume that validation focuses on intervals being checked which we thus build in by using Trinidad's own support for number validation and a helper Facelet component called <face:converter-min-max> that simply implements the case differentiation for the min-max-interval:

<c:choose> <c:when test="#{not empty minimum and not empty maximum}"> <u�:�nsert name="converter-m�n-and-max"/> </c:when> <c:when test="#{not empty minimum}"> <u�:�nsert name="converter-m�n"/> </c:when> <c:when test="#{not empty maximum}"> <u�:�nsert name="converter-max"/> </c:when></c:choose>

Now, we can define our number composition component:

<face:paramBu�lder> <tr:inputText disabled="#{readOnly}" maximumLength="#{maxLength}" contentStyle="#{width:#{width}; text-align:right;" showRequired="true" required="#{required}" columns="" id="#{id}" value="#{model.value}" label="#{msgLabel}" autoSubmit="#{autoSubmit}" immediate="#{immediate}" rendered="#{rendered}" shortDesc="#{shortDesc}"> <c:choose> <c:when test="#{empty type or type==float}"> <c:choose> <c:when test="#{(empty standardConverter and

Page 153: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a Form

[ 140 ]

empty validator) or standardConverter==true}"> <tr:convertNumber �ntegerOnly="false" type="number" m�nFract�onD�g�ts="#{m�nFract�onD�g�ts}" maxFract�onD�g�ts="#{maxFract�onD�g�ts}" pattern="#{pattern}" /> </c:when> <c:otherwise> <c:if test="#{not empty converter}"> <f:converter converterId="#{converter}" /> </c:if> </c:otherwise> </c:choose> <face:converter-m�n-max> <ui:define name="converter-min-and-max"> <tr:validateDoubleRange minimum="#{minimum}" maximum="#{maximum}" /> </ui:define> <ui:define name="converter-max"> <tr:validateDoubleRange maximum="#{maximum}" /> </ui:define> <ui:define name="converter-min"> <tr:validateDoubleRange minimum="#{minimum}" /> </ui:define> </face:converter-min-max> </c:when> <c:otherwise> <c:choose> <c:when test="#{(empty standardConverter and empty converter) or standardConverter==true}"> <tr:convertNumber �ntegerOnly="true" type="number" m�nIntegerD�g�ts="#{m�nIntegerD�g�ts}" pattern="#{pattern}" /> </c:when> <c:otherwise> <c:if test="#{not empty converter}"> <f:converter converterId="#{converter}" /> </c:if> </c:otherwise> </c:choose> <face:converter-m�n-max> <ui:define name="converter-min-and-max"> <tr:validateLongRange minimum="#{minimum}" maximum="#{maximum}" /> </ui:define> <ui:define name="converter-max">

Page 154: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 7

[ 141 ]

<tr:validateLongRange maximum="#{maximum}" /> </ui:define> <ui:define name="converter-min"> <tr:validateLongRange minimum="#{minimum}" /> </ui:define> </face:converter-min-max> </c:otherwise> </c:choose> </tr:inputText></face:paramBu�lder>

Trinidad validation may appear to be used in a somewhat complicated way, but this is done in order to achieve an encapsulation of the various validation possibilities as a single Facelet composition component. We could further refine this approach by adding further case differentiation for the remaining validation types provided by Trinidad, but this is something that increasingly depends on the respective project's needs so it suffices to give an idea here for Long and Double.

Another possible issue is performance, because it should be taken into account that each case differentiation with when and otherwise may be a source of repetitive evaluation. This could lead to less than optimal performance depending on the actual contents of the when and otherwise branches, particularly contents full of method binding. However, JSF performance is an area of its own and is not covered in this book as it would fill another book on JSF. The following screenshot shows a simple usage of the fieldNumber composition component:

Page 155: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a Form

[ 142 ]

The fieldSelect componentWe already had a glimpse of this selection input composition component in a variation in Chapter 2, Structuring and Building Pages with Facelets. There we use an approach with panelLabelAndMessage that depicts a general approach for any kind of JSF component to appear in a panelFormLayout. However, when we know that the encapsulated component is a Trinidad component, panelLabelAndMessage is obsolete and we can reduce the composition component to the following:

<face:paramBuilder> <tr:selectOneChoice showRequired="true" required="#{required}" disabled="#{readOnly}" value="#{model.value}" autoSubmit="#{autoSubmit}" immediate="#{immediate}" valuePassThru="#{valuePassThru}" id="#{id}" contentStyle="#{contentStyle} margin-left:#{cellMargin}px; width: #{cellWidth}" label="#{msgLabel}" shortDesc="#{shortDesc}"> <c:if test="#{empty useOwnSelectionObjects or useOwnSelectionObjects==false}"> <f:selectItems value="#{selectProv�der.getSelect(�d)}" /> </c:if> <ui:insert name="ownSelectionObjects" /> <c:choose> <c:when test="#{(empty valuePassThru and empty converter) or valuePassThru==false}"> </c:when> <c:otherwise> <c:if test="#{not empty converter}"> <f:converter converterId="#{converter}" /> </c:if> </c:otherwise> </c:choose> </tr:selectOneChoice> </face:paramBu�lder>

Earlier, in the Create the composition component section of Chapter 2, Structuring and Building Pages with Facelets, the simple attribute was used and set to true. Here, the simple attribute is not used.

Page 156: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 7

[ 143 ]

The way to pass the select items is simplified has already been alluded in the first part of this book; we include the selectItems tag in the composition component itself so that no explicit passing is anymore required unless specified by using a Facelet insert. This is indicated by setting useOwnSelectionObjects="true". A provider object is applied that returns the respective SelectItem[] object based on the given id.

The converter is usually empty as a selection list does not need to convert its items unless its values are directly passed through. This is also supported by Trinidad. So we also apply our case differentiation as known from the other composition components but customized to the requirements here. We only assume a converter is needed if valuePassThru="true". The following screenshot shows a simple usage of the fieldSelect composition component:

Step II: Building the formNow, we are ready to build the form by incorporating component instances of the above component types into an instance of Trinidad's panelFormLayout that has the following attributes:

fieldWidth: This attribute serves to define the width of each input component's input arealabelWidth: This attribute is used to define the width of the label of each input componentmaxColumns: This attribute defines the desired number of columns to be shown which can be at most as high as is passed in this attributerows: This attribute defines the number of desired rows to be shown (this is also influenced by the maxColumns attribute and may thus increase through internal rendering process)

Page 157: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a Form

[ 144 ]

The component rendering works by building up the form, column by column. The order of appearance of the respective input components per column is defined exactly by the order that they appear as children of panelFormLayout. For example, if we take pseudo-annotated, we assume inputi is an instance of a composition component <face:field* .. />

<tr:panelFormLayout maxColumns="3" rows="1"> <�nput1><�nput�><�nput3><�nput�><�nput�><�nput�><�nput�><�nput8> <�nput�></tr:panelFormLayout>

The respective fields appear as follows:

�nput1 �nput� �nput��nput� �nput� �nput8�nput3 �nput� �nput�

Therefore, if one wants to implement a form that has been provided in a design or specification document, an effective way is to simply enumerate the form column-wise and thus obtain the order of sequence of the fields that must be considered when writing the XHTML implementation.

The rows="1" forces that the carriage return happens according to the column building, that is, because of maxColumns="3" we get a new line after the rendering of 3 fields.

Alternatively, by using greater values of rows, the next line is reached after the indicated number of rows unless maxColumns="1".

A next line may also be enforced by using empty instances of Trinidad's inputHidden component tag to fill a line with virtual fields. This way, a line may stop much earlier and may, for instance, only contain a single field but still keep panelFormLayout's alignment.

Regarding internationalization (I18n), the form is either adapted according to the setup of the label and field widths, or to the actual length of the longest label in a column thanks to the panelFormLayout's dynamic rendering. Therefore, if a label in German is longer, the form will expand the respective column in its width to accommodate the longer label.

There is one known situation when the panelFormLayout component behaves somewhat differently. If there is an input component that is made of several horizontally aligned sub components that are not trimmed to a specific column-width, the same happens as in I18n: The whole column is broadened to be able to accommodate a longer component. In a pseudo-annotated example, if we have,

�nput1 = �nput11, �nput1� and �nput� = �nput�1,�nput�� ..

Page 158: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 7

[ 145 ]

We get,

�nput11 �nput1� �nput3 ..�nput� �nput�1 �nput�� ....

Also, note that a form is not simply divisible by means of several panelFormLayouts because the columns are not anymore aligned to each other's panelFormLayout. However, if we take a closer look it is actually possible when we take care to appropriately set the attributes of several panelFormLayout instances, which we inspect in the upcoming section.

Building a form with several panelFormLayout instancesThe original problem solved by several panelFormLayout instances stems from the limitation of single panelFormLayout instance, because it is not capable to deal with forms that contain fields that deviate from each other in their lengths. In a pseudo-annotated example, if we have.

�nput_________________________11 �nput1�

�nput�1 �nput��

We are not able to deal with this formatting by the use of a single panelFormLayout because input22 would have been aligned to input12.

The essential solution approach consists in taking advantage of the attributes of panelFormLayout in combination with row-oriented structuring. This might look surprising as the panelFormLayout is a component that principally works in a column-oriented method.

However, by setting rows="1", including the required number of maximum columns, the row-oriented approach is also possible with the panelFormLayout component. The downside of this is that we need several instances of panelFormLayout; precisely speaking, one per form row. This redundancy hints on the possibilities of further development of this approach. Thus, it comes as no surprise that the Trinidad sandbox contains such a new component.

Let us take a closer look at the approach.

Page 159: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a Form

[ 146 ]

The approachGenerally, for each row of the form we define a panelFormLayout as follows:

<tr:panelFormLayout inlineStyle="width:#{inlineWidth}px;" labelWidth="#{labelWidth}" fieldWidth="#{fieldWidth}" rows="1" maxColumns="#{maxColumns}"> input11 input12</tr:panelFormLayout>

The first point is that we need to take advantage of panelFormLayout's attributes:

inlineStyle: We already know this attribute as one of Trinidad's basic standard tag attributes as explained in Chapter 3, Most Wanted Tags and Tag Attributes. In this context, it serves to set up a maximum width. That is the maximum width reference for the panelFormLayout component.labelWidth: This attribute is needed to set up the standard width of each label so that it does not matter which actual label length is given in each case, unless it is longer. In which case, it would then need to be cut, for example, by using a Facelet function. This function would be used to cut everything larger than this given label width so that the fields start aligned according to this standard label width.fieldWidth: This attribute's purpose in this context is analogous to labelWidth—fields will not become larger than the given value for this attribute and so the next column of fields will perfectly align to the former column.rows: This attribute is set to "1" and so is used to have the panelFormLayout displaying a single row.maxColumns: This attribute allows setting the maximum number of columns and is needed here to ensure that the formatting calculates the same number of columns for each single row of panelFormLayout.

The second main point here is that the inlineWidth, labelWidth, and fieldWidth values must remain the same for all instances of panelFormLayout except for labelWidth or fieldWidth of those that need to deviate as for the first row of the preceding example. So, for instance, let us take a look at the following form of three rows:

�nput11 �nput1�

�nput�1 �nput��

�nput31 �nput3�

Page 160: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 7

[ 147 ]

This would be implemented as follows:

<tr:panelFormLayout inlineStyle="width:#{inlineWidth}px;" labelWidth="#{labelWidth}" fieldWidth="#{fieldWidth}" rows="1" maxColumns="#{maxColumns}"> input11 input12 </tr:panelFormLayout>

<tr:panelFormLayout inlineStyle="width:#{inlineWidth}px;" labelWidth="#{labelWidth}" fieldWidth="#{fieldWidth}" rows="1" maxColumns="#{maxColumns}"> input21 input22 </tr:panelFormLayout>

<tr:panelFormLayout inlineStyle="width:#{inlineWidth}px;" labelWidth="#{labelWidth}" fieldWidth="#{fieldWidth}" rows="1" maxColumns="#{maxColumns}"> input31 input32 </tr:panelFormLayout>

Again, the important point to be observed here is that #{inlineWidth}, #{labelWidth}, #{fieldWidth}, rows, and #{maxColumns} are all the same throughout the applied three instances of panelFormLayout. To achieve a deviation, we can change one of these instances of panelFormLayout by changing one of its width attributes; typically the fieldWidth could be left out so that the field box may expand beyond the fixed field widths of the other instances.

Finally, note that tab indices are not yet implemented in Trinidad. Instead, as of version 1.2.10 or earlier, there exist various design approaches. One of which will be implemented in future releases (https://issues.apache.org/jira/browse/TRINIDAD-888).

Currently, tabbing occurs somewhat curious because it is column-wise in panelFormLayout. On the other hand, it is also possible to implement a JavaScript-based solution that leverages the composition components defined in the foregoing sections.

Page 161: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a Form

[ 148 ]

Step III: Decorating the form with Trinidad's form submission controlsDepending on which fields are to be sent together to effect an action, the form is possibly decorated with sub forms. In a basic situation, using a simple Trinidad form component suffices perfectly when all the fields have to be sent at once. By the way, Trinidad's form component is not like the JSF form a container, that is, it does not count when child components are identified by their ID. This makes it easier to identify its children as they do not need the form's id as prefix. Such simple situations usually involve a button component below the form positioned in its own line, for example, to submit registration data provided in a form:

<tr:form>

<tr:panelFormLayout maxColumns="3" rows="1">

<�nput1><�nput�><�nput3><�nput�><�nput�><�nput�><�nput�><�nput8> <�nput�>

</tr:panelFormLayout>

</tr:form>

Subform can be used when only certain fields are sent as part of a form or validation is to be restricted to only certain fields. For instance, the first couple of field pairs may be sent independently using a commandLink (or also a commandButton):

<tr:form>

<tr:panelFormLayout maxColumns="3" rows="1">

<tr:subform �d="sub1">

<�nput1><�nput�><tr:commandL�nk ../>

</tr:subform>

<tr:subform �d="sub�">

<�nput3><�nput�><tr:commandL�nk ../>

</tr:subform>

<�nput�><�nput�><�nput�><�nput8><�nput�>

</tr:panelFormLayout>

</tr:form>

The input5 to input9 fields are always sent along with each pair, but only one of both pairs is sent. We can see in the following concrete example how we can gracefully solve validation of a conditional part of a form, thanks to Trinidad subforms.

Page 162: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 7

[ 149 ]

Processing of a part of a form by means of Trinidad subformsA situation that occurs in one or the other web application is the usage of a data profile that changes during a user's session depending on what the user types in other forms. In the following example, we will strip this down to two fields—a tea sort which represents the data profile during such a session and the number of tea units a user might order. So if the user types in another tea sort, (in the lower subform) the upper subform that contains the tea sort data profile is updated accordingly. Moreover, the user may also type in a requested number of tea units. The application returns the number of remaining tea units for the given tea sort and replaces the number of units passed by the user. This example illustrates the following aspects:

What fields are passed depending on which subform is passed (which, in turn, depends on the location of the command button or command link, that is, in which subform it is placed)Which fields are updated, how they are updated, and what the user sees in the end on the browser

The focus of this example is on the first aspect. However, it is also of interest to see how fields are updated, which can be a special issue, and which is why it is also a part of this example.

Let us first take a look at the XHTML:

<form..> <tr:subform �d="sf1" >

<face:fieldText id="fieldTeaSortCurrent" label="currentTeaSort" model="#{pageFlowScope.teaSort}" part�alTr�ggers="::sf�: cmdButton" />

</tr:subform> <br/><br/>

<face:fieldNumber required="true" label="teaUnits" id="fieldTeaUnits" model="#{pageFlowScope.teaModel.number}" part�alTr�ggers="sf�:cmdButton"

type="integer" minimum="1" maximum="100" /> <br/><br/>

<tr:subform id="sf2"> <face:fieldText id="fieldTeaSort" label="teaSort" model="#{pageFlowScope.teaSort}" part�alTr�ggers=" cmdButton" />

<br/><br/>

Page 163: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a Form

[ 150 ]

<tr:commandButton id="cmdButton" partialSubmit= "true" text="Process" act�on="#{controllerInteract�on.doSubform}" block�ng="true" />

</tr:subform></form>

In this code, we can see these aspects as follows:

Two subforms are used—the first one contains the current tea sort and the second one the tea sort typed in by the user. They are activated by a click on the Process button that submits the second subform. Note that both subforms internally use the same domain model.There is yet a third field that is right in the middle of the page and neither belongs to the first, nor to the second subform. We have the constellation presented before where inputs are given that do not belong to any subform, but which are always sent along if one of them is sent.

The doSubform method processes the user input as follows:

public void doSubform(){ log.info("doSubform called! Received:"); Map<String,Object> map = Navigator.getTrinidadContext().getPageFlowScope(); UIViewRoot uiv = Navigator.getFacesContext().getViewRoot();

TeaModel teaModel = (TeaModel)map.get("teaModel"); log.info("- teaModel number of units:"+teaModel.getNumber()); String teaSort = (String)map.get("teaSort"); log.info("- teaSort:"+teaSort);

UIXEditableValue uev = ((UIXEditableValue) uiv.findComponent("formContent:sf1: fieldTeaSortCurrent")); log.info("- currentTeaSort:"+uev.getValue());

uev.resetValue();

map.put("teaSort", checkAndReturnTeaSort(teaSort));

teaModel.setNumber( calculateRemainingTeaUnits(teaSort, teaModel.getNumber())); map.put("teaModel",teaModel);

}

Page 164: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 7

[ 151 ]

So by simply using a couple of log statements, we can find out what actually is received from the browser client that we can see in the following console output. Another interesting detail is that in order to properly refresh the value of the current tea sort by means of PPR, we have to reset the value of the upper form's field fieldTeaSortCurrent. Otherwise, PPR would not work correctly in this case. This is due to the somewhat special situation where the user changes a value that is actually changed again, then by the application itself. For such cases, PPR has not been properly designed but at least Trinidad is equipped with this little workaround.

Let's crosscheck the suggested behavior. If we type in White Tea for the Tea Sort, Green for Current Tea Sort, 10 for Tea Units, and click on Process we receive the following log output:

�1:��:30,3�� INFO [..] doSubform called! Rece�ved:

�1:��:30,3�� INFO [..] - teaModel number of un�ts:10

�1:��:30,3�� INFO [..] - teaSort:Green

�1:��:30,3�� INFO [..] – currentTeaSort:Green

Therefore, the behavior is confirmed as expected:

The tea model number is not in any subform, but it has been passed as expected with the value of 10 units as typed in by the userteaSort and currentTeaSort both have the same value because they reference exactly the same domain

Finally, when looking at the result screen we can see that the refresh has worked properly and that a remaining number of tea units have been calculated and returned in the tea units' field. This is shown in the upcoming screenshot. Moreover, the tea sort fields have been updated accordingly—the check method has returned what it could find under the keyword Green, that is, Green Tea.

Page 165: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a Form

[ 152 ]

Step IV: Adding a general message areaFinally, what remains is to add—usually at the top of the main content—an area where general messages, warnings, and errors are displayed. Note that messages pertained to the respective input component may be shown here, but in JSF, component-specific messages are by default always shown next to the respective component. It is not entirely trivial to support deviating behavior because it requires suppressing the JSF component-related messages. Trinidad's messages component can be applied as follows:

<tr:messages globalOnly="true" styleClass="message"/>

The globalOnly attribute restricts the component to only show general messages not specific to a certain input component (component unrelated messages).

Furthermore, by taking advantage of Trinidad's statusIndicator component and its busy and ready facets, we can enhance the system's communicability by automatically providing a message or an icon symbol while the system is busy:

<tr:statusInd�cator>

<f:facet name="busy">

<tr:outputText value="#{messages[‘systemBusy']}" />

</f:facet>

<f:facet name="ready">

<tr:messages globalOnly="true" styleClass="message"/>

</f:facet>

</tr:statusInd�cator>

SummaryIn this chapter, we have seen the process of developing forms. We started by creating a couple of composition components that in a second step were applied for the actual form to be created. In the second step, we saw how a form can also be hierarchically structured and contain further forms, so called subforms to control what is actually submitted to the application. This can either be used to simply pass those values that are required for processing a group of related inputs while others are ignored, or to (possibly included in this task) only validate that group while the validation of other groups of related inputs are ignored. For a single input, note that the much simpler alternative of using the JSF immediate attribute still remains attractive. Finally, we have added a message area to display those messages that are not field-specific but general application warnings, information, or errors. To get proper feedback while the application is away and busy processing, we have added another Trinidad component that allows displaying exactly this status information during such processing, including any kind of partial-page rendering as well.

Page 166: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Growing a TreeThis chapter deals with Trinidad's tree components and models, while exemplifying their application. Moreover, further orientation is given as to the right choice of tree depending on the purpose.

Trinidad's offering regarding tree components is rather comprehensive, and yet by looking at the class hierarchy, it is not difficult to get the gist. We will cover the following topics in this chapter:

An overview of the structure and features of Trinidad's tree componentsAn introduction to Trinidad's tree models and viewersHow to create simple tree model instances that work with Trinidad's tree componentsHow to integrate a Trinidad tree model as a Seam componentHow to work with the tree to use it for panel-based navigationHow to apply the Trinidad tree component backed by a Seam tree model componentHow to create one's own tree model to work with Trinidad's tree componentsHow to traverse a Trinidad tree backed by one's own tree model

Trinidad's tree componentsAlong with other major Trinidad components, such as table and chart, we find the tree components, such as tree and treeTable in the package org.apache.myfaces.trinidad.component, precisely in the core.data subpackage. As a base model we find TreeModel, an abstract model that is located in the org.apache.myfaces.trinidad.model subpackage. Let us have a look at the provided tree support.

Page 167: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Growing a Tree

[ 154 ]

The following are the supported models:

TreeModel: It is the base model class for all models of tree-like components and usually appears as type indicationChildPropertyTreeModel (subclass of TreeModel):

no lazy-load support (but, of course, node data is mutable)implements all of the abstract methods of TreeModel and is thus a fully fledged tree model that can be applied out of the box

MenuModel (subclass of TreeModel): It is used for models of menu-like components that include navigation to entire pages; thus, without PPR and therefore less interesting, so not covered here BaseMenuModel (subclass of MenuModel): It is a concrete implementation of MenuModel (not covered here for the same reason as MenuModel)

The following are the supported viewers:

tree: It is the main component to render a tree model and has the expected tree component behavior:

proper hierarchical display of nodes and nested nodestree-children-based linking to pages or sub views (for example, panels)proper refresh behavior to ensure the current tree model is always consistent with the current visual state

node items are flexible enough to be made of arbitrary components

navigationTree: It features navigation to concrete pages using BaseModel extended tree models (so not covered here for the similar reason given for MenuModel)treeTable: It is presented along with the table component in the upcoming chapter

In the following section, we will focus on the main stream of tree usage that is a combination of Trinidad's tree component and its out-of-the-box model ChildPropertyTreeModel.

°

°

°

°

°

°

Page 168: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 8

[ 155 ]

ChildPropertyTreeModel—Trinidad's out of the box modelThe usage of this model is fairly easy to build once its main methods are identified:

setWrappedData: It is used to pass the hierarchical tree data to this model (refer to the upcoming section titled Creating a TreeNode Model)setChildProperty: It is used to set the name of the hierarchical tree data property that contains the children of each parent (as usual for such recursive parent-child recursive structures)

Therefore, at object creation time we simply call the following method:

/** * used to setup the tree node hierarchy at runtime * * @param tree is the tree node hierarchy to setup the tree model */public void create(TreeNode tree){ this.setWrappedData(tree); this.setChildProperty("successors");}

Here, successors is the name of the property that we have chosen to reference the children of the hierarchical tree data model passed as tree. This of course, must have been created earlier.

Creating a TreeNode ModelThe hierarchical tree data model called root is an instance of a single tree node that is linked to its children which are (recursively) their own tree nodes as well. So a typical class definition of such an object looks as follows:

package com.test.TrinidadSeamidadApplication;import java.util.ArrayList;

publ�c class TreeNode

{ public final static String rootInclude=""; public final static String rootIncludeLabel="MyTrinidad"; private boolean rendered=true;

Page 169: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Growing a Tree

[ 156 ]

Here, we introduce a couple of String objects to keep the state of the root node with a certain label, and a certain include page which in this case remains empty as the root is by definition set to disabled (not clickable).

/** * to set the path of the include XHTML file that is shown in the * rsp. panel */ private String include;

/** * to set the label of the panel where the node is shown */ private String label;

These properties are the main ones for a node, because we set up which include page and label is to be used.

/** * - used to set which panel to use for the rsp. node * - defaults to the content panel because the other one is only * used to document the content panel * - but if you set this to false the content of the rsp. node * would be shown in the top panel */ private boolean content=true;

/** to setup the hierarchical tree structure we require a * recursive parent-child(ren) structure */ pr�vate ArrayL�st<TreeNode> successors;

Now, we get more into the details of the implementation. The design assumes a double panel structure that consists of a content panel and a description panel—the content panel as the bottom panel and the description panel as the top panel. Of course, we could take this panel design as the basis for other panel designs with more panels and at other locations. Please refer to the The accordion and showDetailItem components section of Chapter 6, Building a Panel-based Content, for further details on the panels.

The successors are the children of the respective node that are themselves TreeNode as well. Therefore, we obtain a recursive structure that allows the creation of a tree of panel-linked objects.

Page 170: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 8

[ 157 ]

We set up the content panel to be the default panel for the display of content, that is, the bottom panel will be used for the display of any type of content by default if a node is created using the following constructor:

public TreeNode(String include, String label) { super(); this.include = include; this.label = label; }

The properties, include and label, are used to set the include file of rsp. panel, which is actually the rsp. panel content, and the panel title; next follow the getter and setter for successors:

publ�c ArrayL�st<TreeNode> getSuccessors()

{ return successors; }

publ�c vo�d setSuccessors(ArrayL�st<TreeNode> ch�ldren)

{ this.successors = children; }...}

Remember that the successors attribute is known to the model, thanks to having its name declared through the setChildProperty method.

Building up a tree modelBy using a little helper method we call addNode, we can easily build our hierarchical tree data structure:

private void addNode(String nodeId, String nodeLabel, ArrayList<TreeNode> successors) { TreeNode node = new TreeNode(nodeId,nodeLabel); successors.add(node); }

Page 171: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Growing a Tree

[ 158 ]

Therefore, we can create the successors child by child where each child is a tree node linked to a panel. All in all, we create a tree made of a list of children on the first hierarchy level:

/** * Default tree nodes * * @return default tree node hierarchy */ @Create public void setupTreeNodes() { TreeNode root = new TreeNode(TreeNode.rootInclude, TreeNode.rootIncludeLabel);

We profit from Seam by using its Create annotation so that at creation time of the model, it is initialized by default.

Moreover, we see how to generate the tree's root that is linked to an empty include file. Remember, the root is to be without function and will thus be disabled for clicks. Next, the one-level hierarchy list is generated, as follows:

ArrayList<TreeNode> successors = new ArrayList<TreeNode>(); root.setSuccessors(successors); addNode("ch.I-1/authorization", "Chapter 1", successors); addNode("ch.I-2/fieldSelect", "Chapter 2", successors); addNode("ch.I-3/empty", "Chapter 3", successors); ... create(root); }

At the end of this method the create method is called, which we have seen in the first section of this chapter.

Extending the ChildPropertyTreeModel to a Seam componentTo surface the model in the most direct and yet encapsulated way we extend the ChildPropertTreeModel and make it a Seam component as follows:

@Name("controllerTree")publ�c class ControllerTree extends Ch�ldPropertyTreeModel{ @In Navigator navi; @In ControllerPanel controllerPanel;

Page 172: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 8

[ 159 ]

publ�c TreeModel getTree() { return this; }

Therefore, we have a Seam component called controllerTree that returns a tree model that it is itself which works very well with Trinidad's tree tag because this Seam component is an instance of an extension of ChildPropertyTreeModel. To access the panels we use the panel controller which is why we inject it into this class.

Preparing the panels for navigationThe same holds for navigation, as we need navigation to move to the display of the respective panels as response to the user click on the respective node.

public void navigate(ActionEvent event) { Map<String,Object> map = event.getComponent().getAttributes(); boolean isContent = ((Boolean)map.get("isContent")). booleanValue(); // if isContent is false, do not use the main content panel but // the description panel area PanelModel panel; if(isContent) { panel = controllerPanel.getContentPanel();

panel.setOpened(true); panel.setRendered(true); PanelModel descPanel = controllerPanel.getDescriptionPanel(); // we reset the description panel to no description; // alternatively, we might provide information for all the // panels but we use this as a way to inform the reader which // chapters have examples and which are more general and no // specific ones descPanel.setInclude("�nfoSeeBook");

descPanel.setLabel("Descr�pt�on see book");

Here, we have the first case (a contents is to be shown in the contents panel) where we mainly setup the content panel—it needs to be selected, opened, and rendered. We also have to take care of the description panel where we show general information.

Page 173: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Growing a Tree

[ 160 ]

We could use this here for the display of concrete information on the respective contents but we choose to inform the reader in a more general way by referring to the respective chapter.

} else { panel = controllerPanel.getDescr�pt�onPanel(); PanelModel contPanel = controllerPanel.getContentPanel(); // see above comment on the description panel reset contPanel.setInclude("layout/empty"); contPanel.setLabel(""); }

Otherwise, we setup the content panel to remain empty and select the description panel for further setup. This enables us to display concrete information for a certain example. We use this to display information where the example can be seen in particular, as it is a general feature of the entire demo application.

Applying the navigation component for basic navigation controlNow we come to the heart of this method:

panel.setInclude((Str�ng)map.get("�nclude")); panel.setLabel((Str�ng)map.get("label")); nav�.getTr�n�dadContext().addPart�alTarget( nav�.getFacesContext().getV�ewRoot(). f�ndComponent("packtAccord�on")); }...

All navigational behavior is going to be increasingly encapsulated in navi, a navigation controller that is injected where navigation is necessary. Also in controllerPanel, a controller for the panels, that is injected as well because we setup the panels according to the choice in the tree menu.

Furthermore, let me remind you once more that we need to make this component available to the XHTML surface that, perhaps surprising, we can simply do by returning the controller itself through the getter getTree because it is a ChildPropertyTreeModel at the same time.

Probably the most interesting part of this tree controller is the addPartialTarget method call. Therefore, we finally use PPR programmatically to refresh the panelAccordion to reflect the updated panel models.

Page 174: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 8

[ 161 ]

Using tag-based PPR is not an alternative for a tree because—due to the stamping approach—no ID can be assigned to the commandLink tag. Even if we could, it would be awkward to indicate for each node a PPR trigger in the panelAccordion!

Creating the XHTMLThe only thing that remains is a fairly straight-forward XHTML that applies the tree tag together with the nodeStamp facet required to build the display of each node. Implicitly, a loop is run for each node encapsulated in a Facelet ui:fragment that contains a commandLink inside a rowLayout ensuring that the node is concisely kept in a single line:

<tr:tree id="navigationTree" value="#{controllerTree.tree}" var="node" �n�t�allyExpanded="true">

The tree tag attributes setup the model connection specified in an expanded state so all nodes, each one identified by var set to node, are opened at first display. The value attribute references the tree controller's getTree method.

This means a call of the getTree method is to be expected within the tree rendering process (at least once depending on Trinidad's tree rendering process). The attribute var identifies the loop element that is the current node of all of the iteration of the loop.

Using the nodeStamp facet to generate the treeNext, follows the actual nodeStamp facet:

<f:facet name="nodeStamp"> <ui:fragment> <trh:rowLayout rendered="#{node.rendered}">

Here, we can see the rowLayout tag to ensure each node is kept in single line. It is only rendered if the node's property of the same name is true. To be able to use the nodeStamp facet we need the Facelets fragment tag, otherwise the tree tag's loop would not be possible in a Facelets environment.

Page 175: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Growing a Tree

[ 162 ]

Using a commandLink to create the clickable tree nodeNow follow the core of the node rendering:

<tr:commandLink text="#{node.label}" act�onL�stener="#{controllerTree.nav�gate}" part�alSubm�t="true"

The actionListener references the navigate method so it is called on each click of a node. As we have seen from the code of the navigate method, this reference to the navigate method actually means a PPR call, which is arguably fine as it indicates a potentially efficient approach (instead of rebuilding the whole page).

Next is the setup of each tree item's disabled state:

d�sabled="#{empty node.�nclude or

(controllerTree.contentPanel.include eq node.include)}">

Therefore, a node is disabled if there is no link to be clicked; this means, that the include attribute is empty. It is also disabled if its include file is already being shown.

Passing the node parameters to the navigation controlThe code concludes with the parameter passing where the include file to link to, the content indication, and the label of the panel are involved:

<f:attr�bute name="�nclude" value="#{node.�nclude}" />

<f:attribute name="isContent" value="#{node. isContent}" /> <f:attribute name="label" value="#{node.label}" /> </tr:commandLink> </trh:rowLayout> </ui:fragment> </f:facet></tr:tree>

We profit from JSF's attribute tag that allows adding further attributes to its parent tag. Therefore, in the navigate method we can easily look them up by checking out the attributes map of the parent tag (in our case, the commandLink tag, see the navigate method of the tree controller).

Page 176: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 8

[ 163 ]

In the following screenshot, we can see the resulting Trinidad tree that is backed by the ChildPropertyTreeModel:

Extending the model-view tree coupleThe model-view tree combination, an alternative to ChildPropertyTreeModel or tree, is about focusing on a purely tree focused implementation of the tree model. The point is that Trinidad's implementation of the tree functionality is somewhat arguable in its efficiency as it tries to content tables and trees at the same time.

Anyhow, Trinidad's clear model–view separation allows providing a model implementation purely dedicated to the tree functionality. This is what we are going to offer in the upcoming section.

Page 177: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Growing a Tree

[ 164 ]

Preparations for the new tree modelBefore we head into the new tree model, we should take a bit of care regarding our tree node design. As a matter of fact, our new tree model will require a few additional features. Thus, it is time to take a look at what a tree node should at least abstractly provide. Then, we can specialize further and define tree node classes that implement additional behavior. It is a simple, non-dynamic, and yet effective design.

The properties of the AbstractTreeNodeThe beginning of our AbstractTreeNode class contains the declarations for all the required properties:

public abstract class AbstractTreeNode { public final static String rootInclude=""; public final static String rootIncludeLabel="MyTrinidad"; protected boolean dialog; protected boolean popup; protected boolean rendered = true; protected boolean opened = true; protected String include; protected String label; protected boolean content=true; protected String prepareMethodName;

protected List<AbstractTreeNode> successors = null;

Apart from prepareMethodName there is nothing really new here, we just abstracted the TreeNode to an AbstractTree, that is, now most of the properties are protected and the class itself has become abstract; prepareMethodName is the method's name that is used to load the respective data model with contents presented throughout the next chapters.

The AbstractTreeNode constructorsWe then follow the constructors which have changed their type to AbstractTreeNode, as follows:

public AbstractTreeNode(String include, String label) { this.include = include; this.label = label; } public AbstractTreeNode(String include, String label, boolean isContent)

Page 178: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 8

[ 165 ]

{ this.include = include; this.label = label; this.contentbbbbbb = isContent; }

New and modified helper methods A new helper method is introduced to aid in setting up a single tree node respective to its basic properties:

protected AbstractTreeNode setupNode(AbstractTreeNode node, boolean isPopup, tring... prepareMethodName) { //show them all in Trinidad dialogs :) node.setDialog(true); node.setPopup(isPopup); if (prepareMethodName.length>0) node.setPrepareMethodName(prepareMethodName[0]); return node; }

Now, follow the addNode methods in their abstract version. They now call an addNode method that has to be implemented in the specific implementations of this AbstractTreeNode:

protected void addNode(String include, String nodeLabel, List<AbstractTreeNode> successors, String... prepareMethodName) { addNode(include, nodeLabel, successors, false, prepareMethodName); }

protected void addNode(String include, String nodeLabel, List<AbstractTreeNode> successors, boolean isPopup, String... prepareMethodName) throws NotSupportedException { addNode(include, nodeLabel, successors, isPopup, true, prepareMethodName); }

protected abstract vo�d addNode(Str�ng �nclude, Str�ng nodeLabel, L�st<AbstractTreeNode> successors, boolean �sPopup, boolean �sContent, Str�ng... prepareMethodName);

Page 179: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Growing a Tree

[ 166 ]

The abstracted getters and settersFinally, there are the getters and setters of which we just want to show the successors as they have changed regarding their types to AbstractTreeNode:

public List<AbstractTreeNode> getSuccessors() { return successors; } public void setSuccessors(List<AbstractTreeNode> successors) { this.successors = successors; }}

Now, we can implement our specific tree node classes. We start by refactoring the TreeNode:

The new TreeNode implementation is now short and easyWe shall see that the new TreeNode implementation is now short and easy. After extending from AbstractTreeNode this is how the class looks:

public class TreeNode extends AbstractTreeNode{

public TreeNode(String include, String label) { super(include, label); }

public TreeNode(String include, String label, boolean isContent) { super(include, label, isContent); }

Obviously, we do not need to do much in the constructors here because in TreeNode we are content with what they already have in the abstract version. The specific change is just here:

@Override protected void addNode(String include, String nodeLabel, List<AbstractTreeNode> successors, boolean isPopup, boolean isContent, String... prepareMethodName) {

Page 180: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 8

[ 167 ]

successors.add(setupNode(new TreeNode(�nclude, nodeLabel, �sContent), �sPopup, prepareMethodName)); }}

It is not really so surprising as we simply apply the provided helper methods to implement what we already had before (only in a much more concise and clearer way).

The new tree node implementation for the new tree modelThis is where additional behavior is required. The class called NavigationTreeNode is not very long compared to TreeNode but has a few conspicuous additions, as follows:

public class NavigationTreeNode extends AbstractTreeNode { private NavigationTreeNode predecessor = null;

Therefore, we now keep track of the predecessor, the parent object in our tree structure. This is basically the difference between TreeNode and NavigationTreeNode. For the constructors, this means that we now have to pass the parent object as well:

public NavigationTreeNode(NavigationTreeNode node, String include, String label, boolean isContent) { super(include, label, isContent); predecessor = node; }

public NavigationTreeNode(NavigationTreeNode node, String include, String label) { super(include, label); predecessor = node; }

We add a getter method for the parent:

public NavigationTreeNode getPredecessor() { return predecessor; }

Page 181: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Growing a Tree

[ 168 ]

Moreover, we want to find out if the current node has any children (successors):

public boolean hasNoSuccessors() { List<?> successors = getSuccessors(); return successors==null || successors.isEmpty(); }

This is almost everything to this kind of tree node. The only thing left is to implement the addNode method which has to consider this, again as the parent:

public void addNode(String include, String nodeLabel, List<AbstractTreeNode> successors, boolean isPopup, boolean isContent, String... prepareMethodName) { NavigationTreeNode successor = new NavigationTreeNode(this, include, nodeLabel, isContent); successors.add(setupNode(successor, isPopup, prepareMethodName)); }}

The new tree model—based on Trinidad's abstract TreeModelIt is time to create the new tree model. This is not really difficult; all we need to do is implement a couple of methods of Trinidad's abstract TreeModel plus add the required state to keep the new tree model:

@Name("controllerNavTree")@Scope(ScopeType.SESSION)public class ControllerContainerTree extends TreeModel { private int selectedNodeKey = -1; private NavigationTreeNode root; private List<AbstractTreeNode> successors = null; private AbstractTreeNode predecessor = null;

Therefore, this is the additional state—we keep track of the currently selected tree node, the tree root, the successors (the children), and their predecessor (parent). The model is enhanced to work as a Seam component as we combine it with light-weight controller logic as we already have done for the former tree controller-model that extended the ChildPropertyTreeModel.

Page 182: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 8

[ 169 ]

The session scope is applied to keep this state across the requests (another scope superior to the request scope would have done as well, for instance the conversation scope) otherwise, the tree would be rebuilt at each request and we would not get far as a user when, for example, trying to expand a node.

Test out the row disclosure by adding a RowDisclosureEvent listenerTo test out the row disclosure, that is expanding tree nodes with children, also called sub structures or containers (in Trinidad lingo), we add the appropriate event listener:

public void doRowDisclosure(RowDisclosureEvent event){ log.info("doRowDisclosure");}

Another tree content to better try tree traversalFor the view we provide content, other than the main tree for our demo application. It is simply a smaller tree but with more sub structure:

@Create public void setupTreeNodes() { root = new NavigationTreeNode(null, NavigationTreeNode. rootInclude, NavigationTreeNode.rootIncludeLabel); successors = new ArrayList<AbstractTreeNode>(); root.setSuccessors(successors); root.addNode("ch.II-1/panels","Chapter II-1",successors, false, true); root.addNode("info","Chapter II-3",successors, false, true); AbstractTreeNode child = successors.iterator().next(); List<AbstractTreeNode> childSuccessors = new ArrayList<Abstra ctTreeNode>(); child.setSuccessors(childSuccessors); child.addNode("ch.II-2/tryFieldSelect","Chapter II-2 fieldSelect", child.getSuccessors(), "prepareProviderOfField"); // test setRowIndex(0); if(isContainer()) enterContainer(); log.info("rowCount:"+getRowCount()); exitContainer(); log.info("rowCount after move to root:"+getRowCount()); }}

Page 183: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Growing a Tree

[ 170 ]

In the following screenshot, we can see the resulting tree viewer that reflects the example contents and we can see its richer sub structure:

As it can be seen in the last lines, a couple of the container-related methods of TreeModel have been tried. We will see the results in the last section of this chapter when we try out the new model.

The getters to access the new stateBefore we start re-implementing Trinidad's TreeModel, we add a couple of getters that we need to access the tree from the XHTML (getTree, as known from the other tree model controller), the predecessor (parent) of the passed node, and the current successors (children) of the passed node:

public TreeModel getTree() { return this; }

public Object getPredecessor(Object o) { return o!=null ? ((NavigationTreeNode) o).getPredecessor() : null; }

private List<AbstractTreeNode> getSuccessors(Object o) { return o!=null ? ((AbstractTreeNode) o).getSuccessors() : root.getSuccessors(); }

We need to cast to either AbstractTreeNode or NavigationTreeNode to access the respective method. If the node is null, it cannot have a parent which is why we return null. In case of the children, we default to the root's children because we assume the root has been passed.

Page 184: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 8

[ 171 ]

Tree traversal with Trinidad's container methodsWe next go for tree traversal with Trinidad's container methods, for which we need to follow the container methods to traverse the tree. First, we implement the is method:

@Override public boolean isContainer() { return selectedNodeKey>=0 && ! ((NavigationTreeNode)successors.get(selectedNodeKey)). hasNoSuccessors(); }

@Override public boolean isContainerEmpty() { return selectedNodeKey>=0 && ((NavigationTreeNode)successors. get (selectedNodeKey)).hasNoSuccessors(); }

Basically, we say that the node identified by its selected node key is a container if that node has children (only the other way round by negation; that is, when it is not a node that has no children). It is not a container when it simply does not have children.

If we enter such a sub structure, we need to call the enterContainer (but we need to make sure that it has sub structure which we do by using foregoing methods):

@Override public void enterContainer() { if (selectedNodeKey >= 0) { predecessor = successors.get(selectedNodeKey); successors = getSuccessors(predecessor); selectedNodeKey = successors.isEmpty() ? -1 : 0; } }

Page 185: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Growing a Tree

[ 172 ]

Therefore, what needs to be done is quite clear—reassign the state by setting the new parent, the new children, and the new selected node key which is initially 0 as we do not enter a container with a specific child in mind but just default to the first child. Next follows what we do when we leave a container:

@Override public void exitContainer() { AbstractTreeNode selectedNode = predecessor; predecessor = (AbstractTreeNode) getPredecessor(predecessor); successors = getSuccessors(predecessor); selectedNodeKey = findIndex(successors, selectedNode); }

In this case, we need to assign the new parent being the parent of its parent. The new selected node is the parent and the successors are the children of it. For the selected node key we only need to find its key which we simply do by the using the indexOf method of the List:

private int findIndex(List<AbstractTreeNode> list, Object object) { return (list == null || object == null) ? -1 : list.indexOf(object); }

The row key methodsNow, we need to follow all the row key related methods:

@Override public Object getContainerRowKey(Object childRowKey) { return childRowKey == null ? null : getPredecessor(childRowKey); }

@Override public Object getRowKey() { return selectedNodeKey == -1 ? null : successors.get(selectedNodeKey); }

Page 186: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 8

[ 173 ]

These methods are the getters for the row key. The container-related row key getter yields the row key of the container, that is, the parent row key of the passed row key unless it is null. The other, that is, the standard row key getter yields the row key of the selected node key.

Next, we conclude the row key methods with the row key setter:

@Override public void setRowKey(Object key) { predecessor = (AbstractTreeNode) getPredecessor(key); successors = getSuccessors(predecessor); selectedNodeKey = findIndex(successors, key); }

We can see that setting the collection's row key means something similar to entering or leaving a container. The whole state changes because a tree-wide identifier leads to a reset of the currently selected tree structure. Therefore, another parent, children, and selected node key are set.

The row index methodsIn contrast to the row key methods, the row index getters or setters are much simpler as they are relative. So we only need to check the boundaries:

@Override public void setRowIndex(int rowIndex) { if (successors == null) { return; } if (rowIndex < 0 || rowIndex >= successors.size()) { selectedNodeKey = -1; return; } selectedNodeKey = rowIndex; } @Override public int getRowIndex() { return selectedNodeKey; }

Page 187: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Growing a Tree

[ 174 ]

In contrast to the row key, if the passed rowIndex is not out of bounds, it is simply assigned as the selected node key.

The general row methodsTo get the usual information and actual data of the respective node, the following methods must be implemented:

@Override public int getRowCount() { return successors == null ? 0 : successors.size(); }

We have an idea about the number of children that the selected node key actually has (unless no children are given). If we want to access the selected node we may call the following method:

@Override public Object getRowData() { return selectedNodeKey == -1 ? null : successors.get(selectedNodeKey); }

The last row method allows retrieving, if a row is at all available:

@Override public boolean isRowAvailable() { return successors != null && selectedNodeKey >= 0 && selectedNodeKey < successors.size(); }

The table-related methods are implemented as empty methods Finally, we neglect any use of the table-related methods because, as already mentioned, we want to focus only on tree-specific functionality:

@Override public Object getWrappedData() { return null; }

Page 188: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 8

[ 175 ]

@Override public void setWrappedData(Object data) { }}

The controller-enhanced tree modelsWe already have seen earlier, in this chapter, how the TreeModel has been expanded to a light-weight model-controller Seam component. For completeness, we take a look at the former tree controller because it also has changed according to the last refactoring:

@Name("controllerTree")public class ControllerTree extends ChildPropertyTreeModel {

protected static final String SUCCESSORS = "successors";

@Create public void setupTreeNodes() { TreeNode root = new TreeNode(TreeNode.rootInclude,TreeNode. rootIncludeLabel); List<AbstractTreeNode> successors = new ArrayList<AbstractTre eNode>(); root.setSuccessors(successors); root.addNode("ch.I-1/authorization","Chapter I-1", successors); root.addNode("ch.I-2/testFieldSelect","Chapter I-2", successors, "prepareField"); ... create(root); }

We can see that the new AbstractTreeNode is used. The addNode method has been, as already seen in the new TreeModel-based model controller, moved to the AbstractTreeNode:

public TreeModel getTree() { return this; }

Page 189: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Growing a Tree

[ 176 ]

public void create(AbstractTreeNode tree) { this.setWrappedData(tree); this.setChildProperty(SUCCESSORS); }}

This is everything there is to this new version. For obvious reasons, the navigation method has been moved to the navigator controller component, as is also the case with the TreeModel-based model controller. It is clearly notable how simple and clear this model controller component has become now.

Testing internal navigationAs promised earlier, let us take a look at how we can traverse the tree with our new tree model's container methods. Remember that we have added some logger output to the setupNodes method:

// test setRowIndex(0);

�f(�sConta�ner()) enterConta�ner();

log.�nfo("rowCount:"+getRowCount());

ex�tConta�ner();

log.�nfo("rowCount after move to root:"+getRowCount());

The following is the logger output we receive:

1�:�0:33,�33 INFO [..] rowCount:1

1�:�0:33,�33 INFO [..] rowCount after move to root:�

1�:��:��,��� INFO [..] doRowD�sclosure..

So at startup, we make sure that the selected node is the first child. After applying enterContainer, which is the case because isContainer returns true, we get a row count of 1. This is correct because the first child has just one child which was enough for us to test the children sub structure. Next, we move back to the root by calling exitContainer. Logically, the logger should now print a row count of 2, which is the case because our simple tree contents, below the root, have two children.

Page 190: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 8

[ 177 ]

SummaryIn this chapter, we have seen the Trinidad trees from two different model perspectives.

On one hand, we have applied the standard, out of the box Trinidad tree model called ChildPropertyTreeModel. This model allowed a straight-forward implementation of our own tree, filled with our contents.

On the other hand, we have implemented our own basic tree model based on Trinidad's TreeModel that is free from any table-related behavior and thus supposedly more efficient. This includes the implementation of so-called container methods that allow the traversal of the tree. We have also done a review of the tree node design and introduced an abstract tree node to work with a clear and more concise design.

We have loaded the two models with different tree content data to try out the tree's features. Finally, we have taken a look at Trinidad's TreeModel container behavior and learned how entering a container, that is a tree sub structure actually containing the respective children, changes the selected tree state accordingly.

Page 191: Apache Myfaces Trinidad 1.2 A Practical Guide (November
Page 192: Apache Myfaces Trinidad 1.2 A Practical Guide (November

The table and treeTable Components

This chapter deals with Trinidad's table and treeTable component and exemplifies their application. These components serve to display, navigate, and edit tabular data that can be hierarchically structured. They belong to a group of powerful components that are often taken to show off Trinidad's attractiveness as a JSF component library.

In this chapter, we shall cover the following topics:

Using the table component and its special featuresApplying JSF binding to encapsulate the table componentUsing the treeTable component and its special features

The table componentThe table component is one of Trinidad's main components and its power is often one of its key attractions to this framework. We will try out most of the features by starting with a minimal example and increasingly refining it up to the point of a table that takes advantage of all the more interesting features available to the Trinidad table.

The table component's basic aim is to provide a means to list a number of records of equal structure that include navigation to browse through the list, with the option to select a single record or multiple records, among other features.

Page 193: Apache Myfaces Trinidad 1.2 A Practical Guide (November

The table and treeTable Components

[ 180 ]

Typically, it can be used to implement the part of a search dialog where the list of hits is displayed, and where the user selects one or more records. Another common use is the provision of a means to edit a number of domain objects in an operative system, for example, a domain base of book records with each column of the table representing a book property.

The table component in its most minimal usageThe Trinidad table requires at least a few children components to accommodate the columns, and the type of output component used for each column:

<tr:table �d="testTable" value="#{pageFlowScope.tableModel}" var="var">

<tr:column headerText="Nr."> <tr:outputText value="#{var[0]}"/> </tr:column>

Thus, the table component contains a number of column components of which the preceding part is the first to appear on the view (from left to right). Furthermore, a column contains the actual output that is to appear in the respective column—in our example, the respective column of our table model. We use an overall of three columns. The last two are:

<tr:column headerText="Name"> <tr:outputText value="#{var[1]}"/> </tr:column> <tr:column headerText="Class"> <tr:outputText value="#{var[2]}"/> </tr:column></tr:table>

As we use Trinidad dialogs as the basis for all types of display and communication, the model is accessed through the pageFlowScope, as can be seen in the first line. To implement the simplest usage we simply apply a List model. This is why the reference for each column is through an index. Trinidad automatically converts the list model into its corresponding internal collection model. So the list model is initialized with the usual obvious list creation technique:

public Map<String, Object> prepareTableDialogMap() {

List<String[]> list = new ArrayList<String[]>(); list.add(new String[]{"1","yhin zhin","white tea"}); list.add(new String[]{"2","silver dragon", "white tea"});

Page 194: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 9

[ 181 ]

list.add(new String[]{"3","yin lhun white snow","white tea"}); Map<String,Object> map = new HashMap<String, Object>(); map.put("tableModel", l�st);

return map; }

Additionally, a map is created as not only the table may be required to be passed, but potentially other models as well. Bear in mind that the preceding method is devised for the preparation of all the models for a whole dialog. This will probably mean the initialization of several models, which is why Trinidad expects a map to be passed to its dialog launch process. Remember that Trinidad's launch method is defined as follows:

void org.apache.myfaces.trinidad.context.RequestContext.launchDialog( UIViewRoot dialog, Map<String,Object> map, UIComponent eventComponent, boolean isPopup, Map<String, Object> windowProperties)

Therefore, map is the above map that we have created with tableModel as its contents. The following screenshot gives a preview of the default looks of the Trinidad table:

Page 195: Apache Myfaces Trinidad 1.2 A Practical Guide (November

The table and treeTable Components

[ 182 ]

Adding a selection listenerWe would now like to add selection to the table. This includes the following two simple steps:

• Set up the table to display a selection column: We have to add rowSelection="single" to the table declaration to enable single choice selection.

• Set up the selection listener: The table declaration could be extended to include something like selectionListener="#{controllerInteraction.tableSelect}". Here, we would specify a controller called controllerInteraction and the selection of a single line would be followed by the call of a Trinidad selection event listener method called tableSelect. However, such a technique only makes sense when there is really something essential to be done directly after each selection. This is often not the case. Therefore, we resort to a simpler JSF-pure technique that applies an OK button and its corresponding button action event listener that is only called once, and not after, each selection (much less conversation noise). The downside to this approach is that we need to know the ID of the table component which couples view (the table component) and controller tighter.

The result is the following XHTML code:

<tr:table id="testTable" value="#{pageFlowScope.tableModel}" var="var" rowSelect�on="s�ngle">

<tr:column headerText="Nr."> <tr:outputText value="#{var[0]}"/> </tr:column> <tr:column headerText="Name"> <tr:outputText value="#{var[1]}"/> </tr:column> <tr:column headerText="Class"> <tr:outputText value="#{var[2]}"/> </tr:column></tr:table>..<div class="actionButtons"> <tr:commandButton text="OK" action="#{controllerInteraction.tableSelect}" /></div>

Page 196: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 9

[ 183 ]

The tableSelect method is the mentioned action event listener wherein the selection is retrieved. This process is as simple as follows:

public void tableSelect(){ UIXTable table = (UIXTable)navi.getFacesContext().getViewRoot(). findComponent("formContent:testTable"); Object select�on = table.getSelectedRowData();

navi.getTrinidadContext().getPageFlowScope().put( "selection", selection[1]);}

First, we find the component by the usual JSF means. Note that we need to pass an ID that includes the panel's subform because a Trinidad subform is a naming container. Next, we read the selection by using getSelectedRowData to the full object. Indirect index retrieval is avoided, which would also be possible by using getSelectedRowKeys instead of getSelectedRowData. The method closes by putting part of the selection, that is the name part of the selected object (the tea name) into the page flow scope so that the current selection may additionally be shown to the user (in addition to the selected radio button) by the means of PPR:

<div> <tr:outputText part�alTr�ggers="formContent:testTable"

value="#{pageFlowScope.selection}" /></div>

Therefore, the table declaration would be augmented by either setting up the table as a PPR source:

<tr:table id="testTable" value="#{pageFlowScope.tableModel}" var="var" rowSelect�on="s�ngle" part�alSubm�t="true">

Or by setting the commandButton component as a PPR source:

<tr:commandButton id="tableSelectButton" autoSubmit="true" text="OK" act�on="#{controllerInteract�on.tableSelect}" />

And adapting the outputText partialTriggers reference accordingly:

<tr:outputText part�alTr�ggers="tableSelectButton"

value="#{pageFlowScope.selection}" />

Page 197: Apache Myfaces Trinidad 1.2 A Practical Guide (November

The table and treeTable Components

[ 184 ]

Adding sortingThree conditions must be fulfilled to enable sorting on a Trinidad table:

The sortable="true" condition must be set on the respective table columnThe sortProperty="<table model column property> condition must be set where the table model column property is the respective property expression that references the table model property to sort the respective columnThe table model must support sorting which means that the following methods must be implemented:

get/setSortCriteria(List<SortCriterion> criteria)

isSortable(String property)

Fortunately, the internally used CollectionModel already implements these methods. Therefore, in a regular case there is not much to do apart from fulfilling the foregoing two conditions, except for specific deviating sort criteria that is, if no alphabetic sorting is used.

The table declaration now looks as follows:

<tr:table id="testTable" value="#{pageFlowScope.tableModel}" var="var" rowSelection="single"> <tr:column headerText="Nr." sortable="true" sortProperty="0">

<tr:outputText value="#{var[0]}"/> </tr:column> <tr:column headerText="Name" sortable="true" sortProperty="1">

<tr:outputText value="#{var[1]}"/> </tr:column> <tr:column headerText="Class" sortable="true" sortProperty="�">

<tr:outputText value="#{var[2]}"/> </tr:column></tr:table>

The sortProperty is in this case an easy declaration because of the use of the list model as a table model. Generally, the sortProperty is the name of the table model's property for the respective columns. The following screenshot shows what the Trinidad table looks like with enabled default sorting:

°

°

Page 198: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 9

[ 185 ]

Adding a button barIt is already noticeable that there is an additional line required for buttons related to specific functionality provided for the respective table. This line, however, can be saved and a button bar can be placed more intrinsically as part of the table component. To this end, Trinidad provides a table facet called 'actions'. If the button(s) should appear directly below the table, the facet 'footer' is provided. Additionally, the facet 'header' is available to have the button bar at the top of the table but below the 'actions' button bar. The most interesting case is probably the actions facet because it allows saving one line and keeping all the specific table functionality in a single button bar:

<tr:table id="testTable" value="#{pageFlowScope.tableModel}" var="var" rowSelection="single"><f:facet name="act�ons">

<tr:commandButton �d="tableSelectButton" autoSubm�t="true"

text="Subm�t Sel." act�on="#{controllerInteract�on. tableSelect}" />

</f:facet>

<tr:column headerText="Nr." sortable="true" sortProperty="0"> <tr:outputText value="#{var[0]}"/> </tr:column>

Page 199: Apache Myfaces Trinidad 1.2 A Practical Guide (November

The table and treeTable Components

[ 186 ]

<tr:column headerText="Name" sortable="true" sortProperty="1"> <tr:outputText value="#{var[1]}"/> </tr:column> <tr:column headerText="Class" sortable="true" sortProperty="2"> <tr:outputText value="#{var[2]}"/> </tr:column></tr:table>

Remember that moving this button into the actions facet has a side effect on PPR. As the button is now part of the table, the ID of the table must be added as a prefix to the partialTriggers declaration (otherwise the button would not be found) as follows:

<tr:outputText part�alTr�ggers="testTable:tableSelectButton" value="#{pageFlowScope.selection}" />

The following screenshot shows the button that is now part of the table:

Adding detail data sub views and using a POJO data modelNow it is time to upgrade to a richer model that also includes further detail data to be shown when user decides to view more details on a single line. We replace the simple list by a list made of instances of the following POJO:

public class TeaModel { private String name; private String sort; private String number; private String origin; private String company;

public TeaModel(String company, String name, String number, String origin,String sort) { super(); this.company = company; this.name = name; this.number = number; this.origin = origin; this.sort = sort; }}

Page 200: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 9

[ 187 ]

Trinidad's offering includes a facet called detailStamp that enables detail views on single lines. The following table declaration results, along with the new table model:

<tr:table id="testTable" value="#{pageFlowScope.tableModel}" var="var" rowSelection="single" rows="2"> <f:facet name="actions"> <tr:commandButton id="tableSelectButton" autoSubmit="true" text="Submit Sel." action="#{controllerInteraction.tableGrowsSelect}" /> </f:facet> <f:facet name="deta�lStamp"> <trh:rowLayout> Or�g�n: <tr:outputText value="#{var.or�g�n}"/> <tr:spacer w�dth="1" he�ght="1"/> Company: <tr:outputText value="#{var.company}"/> </trh:rowLayout> </f:facet> <tr:column headerText="Nr." sortable="true" sortProperty="number" > <tr:outputText value="#{var.number}"/> </tr:column> <tr:column headerText="Name" sortable="true" sortProperty="name" > <tr:outputText value="#{var.name}"/> </tr:column> <tr:column headerText="Class" sortable="true" sortProperty="sort" > <tr:outputText value="#{var.sort}"/> </tr:column></tr:table>

The following screenshot shows the detailStamp functionality of Trinidad:

The selection action event handler had to be slightly adapted because of the switch to the POJO model:

public void tableGrowsSelect(){ UIXTable table = (UIXTable)navi.getFacesContext().getViewRoot(). findComponent("formContent:testTable"); TeaModel select�on = (TeaModel)table.getSelectedRowData(); navi.getTrinidadContext().getPageFlowScope().put("selection", select�on.getName());}

Page 201: Apache Myfaces Trinidad 1.2 A Practical Guide (November

The table and treeTable Components

[ 188 ]

Adding a search form and pagingFirst of all, we need a search model. We provide a subset of TeaModel to search for origin and tea class ('sort'):

package business;public class TeaSearchModel {

private String sort; private String origin;

public TeaSearchModel(String origin, String sort) { super(); this.origin = origin; this.sort = sort; }

public boolean isEmpty() { return (this.getOrigin().equals("") && this.getSort(). equals("")); }...}

The isEmpty method is a simple, convenience method used to fully reinitialize the table model when nothing is provided in the search. Bear in mind that we do not deal with any middle or back-end tier modeling, so we keep using POJOs created in the presentation layer.

Now, we can declare the search area on our XHTML page:

<div> <tr:panelFormLayout rows="2" columns="1" > <tr:inputText label="Origin:" value="#{pageFlowScope.searchModel.origin}" /> <tr:inputText label="Class:" value="#{pageFlowScope.searchModel.sort}" />

Therefore, we use a few fields to be able to execute a little search in the following (the tag closes with the footer facet where we provide our search button):

<f:facet name="footer"> <tr:panelButtonBar> <tr:commandButton id="searchButton" text="Search" action="#{controllerInteraction.doSearchOnGrowsTable}"

Page 202: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 9

[ 189 ]

autoSubmit="true" /> </tr:panelButtonBar> </f:facet> </tr:panelFormLayout></div>

Hence, we profit from panelFormLayout to get an automatic layout of our search input fields, and we take advantage of panelFormLayout's footer facet. Again, we keep our automated layout. The search is executed by a purely demonstrative search method, as follows:

public void doSearchOnGrowsTable() { Map<String,Object> map = navi.getTrinidadContext(). getPageFlowScope(); TeaSearchModel searchModel = (TeaSearchModel)map. get("searchModel"); List<TeaModel> list = (List<TeaModel>)map.get("tableModel");

We fetch the involved objects from the pageFlowScope where they are supposed to be (remember we put them there ourselves by passing the correspondent map to Trinidad's launchDialog method).

List<TeaModel> result; if(searchModel.isEmpty()) { result = controllerPrepare.retrieveTeaModelList(); } else { if(list.isEmpty()) { list = controllerPrepare.retrieveTeaModelList(); }

Above, we can see some preparation for our little search. If no search is to be done, we just fetch the current result and return it. Otherwise, we prepare the search by fetching the whole list (something that is obviously only done in a demonstrative case such as this one). Next, we actually do the search by simply looping through the current list and looking for some simple matches:

result = new ArrayList<TeaModel>(); for (TeaModel teaModel : list) { if(teaModel.getOrigin().equalsIgnoreCase( searchModel.getOrigin())||

Page 203: Apache Myfaces Trinidad 1.2 A Practical Guide (November

The table and treeTable Components

[ 190 ]

teaModel.getSort().equalsIgnoreCase( searchModel.getSort())) result.add(teaModel); } }

Finally, we save the new tableModel that is the current result of our search:

map.put("tableModel", result); }

Paging could not be simpler to activate since it provides an attribute called rows to indicate the number of lines to show per page. Moreover, we add partialTriggers to the table to get it updated according to the search results:

<tr:table id="testTable" value="#{pageFlowScope.tableModel}" var="var" rowSelect�on="s�ngle" part�alTr�ggers="::formContent: searchButton"

rows="�">

To have PPR find its partial trigger for the table, the partialTriggers declaration instructs PPR to find the button by moving one hierarchy level up and outside of the table container where the button is actually located. The following screenshot shows the Trinidad table component with applied search form, expanded details and action bar:

Page 204: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 9

[ 191 ]

Adding banding and grids for better visibilityBanding and grids are straightforward because they are declared as Boolean attributes of the table tag. We enable horizontal banding to minimize the human eye's fluctuation when viewing longer tables, and activate grids to clearly separate each table cell from each other:

<tr:table id="testTable" value="#{pageFlowScope.tableModel}" var="var" rowSelection="single" partialTriggers="::formContent:searchButton" rows="5" band�ngInterval="1" band�ng="row" hor�zontalGr�dV�s�ble="true"

vert�calGr�dV�s�ble="true">

Making use of JSF binding and Facelets for further encapsulationThis allows encapsulating of a Trinidad table in a way that removes the burden of having to restate structurally identical table declarations each time they are called. Furthermore, a positive side-effect is that a uniform look and feel beyond the component's skinnability can be encapsulated:

encapsulation of grid and bandingencapsulation of formatting of each rowencapsulation of special features such as detail viewsencapsulation of general features such as button bars or sorting

To achieve this encapsulation, a much richer table model is required that serves a fully pre-initialized Trinidad CoreTable object:

public class TrinidadCoreTableModel {

public CoreTable coreTableComponent;

public CoreTable getTable() { return coreTableComponent; } public void setTable(CoreTable tableComponent) { this.coreTableComponent = tableComponent; }

Page 205: Apache Myfaces Trinidad 1.2 A Practical Guide (November

The table and treeTable Components

[ 192 ]

So, we provide a Trinidad CoreTable through a method binding, which is what we need to be able to apply JSF binding on the XHTML side. Next, we need to initialize this model which we do with the following constructor:

public TrinidadCoreTableModel(String[] cols, List<TeaModel> list) { if (coreTableComponent==null) { columnArray = StringUtils.split(cols); coreTableComponent = new CoreTable();

This is the way we create the TableModel, which in this binding case is the full Trinidad table component.

The component construction of CoreTable with new is going to become deprecated and change in JSF 2.0 where JSF's Application object is equipped with a createComponent factory method.

Once the component is created, we set it up to use the passed column components:

for (String columnPropertyName : columnArray) { coreTableComponent.getChildren(). add(addCol(columnPropertyName)); }

Then, we set it to use single selection and the real table model which is our list:

coreTableComponent.setRowSelection("single"); coreTableComponent.setValue(list);

Next, we set the name of the loop variable to var, in order to reference the properties of each record and the number of rows displayed at once:

coreTableComponent.setVar("var"); coreTableComponent.setRows(5);

We conclude the creation and setup of our table component by setting the refresh behavior according to clicking on the search button, and the style that makes sure that scrolling is enabled instead of vertical growth. This process would move the buttons from their usual positions:

coreTableComponent.setPartialTriggers(new String[] {"::formContent:searchButton"});); coreTableComponent.setInlineStyle("height:250px;overflow: auto;"); } }

Page 206: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 9

[ 193 ]

Again, we will create a component by using the current component construction (which is to change in JSF 2.0, see above on CoreTable). This time, we will create a column component which is used to build up the table component:

private CoreColumn addCol(String columnPropertyName) { CoreColumn col = new CoreColumn();

We now apply a convention of the passed column property names where we assume ":" to separate each column property name from its label so the first entry is the id of the column:

//convention String[] columnInfo = columnPropertyName.split(":"); col.setId(columnInfo[0]);

For each column's content we use CoreOutputText (note JSF 2.0 is going to change the creation from new to application. createComponent(..), see also above comments), because we just want this simple component to provide a list of hits to select from:

CoreOutputText text = new CoreOutputText(); String headerLabel = columnInfo[0]; ValueExpression<Object> ve = Expressions.instance(). createValueExpress�on("#{var." + columnInfo[1] + "}"); text.setValueExpress�on("value", ve.toUn�f�edValueExpress�on()); col.setHeaderText(headerLabel); col.getChildren().add(text); return col; }}

To create a ValueExpression, which is what we need to set the value attribute of CoreOutputText, we profit from Seam's EL and value expressions factory method createValueExpression and convert it to the standard (unified) ValueExpression.

Now, the only thing that remains to be done is to set this wrapper-type model in the dialog:

public Map<String, Object> prepareTableBindingDialogMap() { TeaSearchModel searchModel = new TeaSearchModel("",""); Tr�n�dadCoreTableModel tableModel = new Tr�n�dadCoreTableModel(

Page 207: Apache Myfaces Trinidad 1.2 A Practical Guide (November

The table and treeTable Components

[ 194 ]

new Str�ng[]{"number", "name", "sort"}, retr�eveTeaModelL�st());

Map<String,Object> map = new HashMap<String, Object>(); map.put("tableModel", tableModel); map.put("searchModel", searchModel); return map; }

The basic difference is that now, we use the new binding model whose constructor expects a list of property names and the actual table data model.

Creating the XHTML: the reduction to a single lineWe can now enjoy the immense reduction which merely condenses the table declaration to the following single line:

<tr:table �d="testTable�" b�nd�ng="#{pageFlowScope.tableModel.table}" />

A subtle difference to the usual value binding is that the JSF binding attribute expects a method binding, meaning that table must be associated with a getter method. The following screenshot shows the resulting Trinidad binding table:

Page 208: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 9

[ 195 ]

The treeTable componentThe treeTable component leverages the table component, augmenting its capabilities by tree functionality. Again, what can be said about the table component also holds for this component—it is a very powerful component making Trinidad a key JSF component framework (it is interesting to see that other libraries vary very much in availability and quality of such a component).

Again, as in the foregoing section, we will start with a simple example and refine it to include all the major features available to this component.

The treeTable component in its most minimal usageSimilar to the Trinidad table, the Trinidad treeTable requires a few children components to accommodate the columns and the type of output component used for each column:

<tr:treeTable �d="testTreeTable" value="#{pageFlowScope. treeTableModel}"

var="node" initiallyExpanded="true"> <f:facet name="nodeStamp">

<tr:column headerText="Name">

<tr:outputText value="#{node.label}"/> </tr:column> </f:facet> <tr:column headerText="Include" > <tr:outputText value="#{node.include}"/> </tr:column> <tr:column headerText="Method"> <tr:outputText value="#{node.prepareMethodName}"/> </tr:column></tr:treeTable>

Now, the nodeStamp facet sounds familiar and it is actually the same as the one used in the tree component. In the treeTable component, it has additional meaning because it represents the key property (primary identifier of a hierarchical element). Also known to the users of the tree component is the initiallyExpanded attribute, so all the nodes are opened at first display.

Page 209: Apache Myfaces Trinidad 1.2 A Practical Guide (November

The table and treeTable Components

[ 196 ]

As can be seen below, the tree table model we have chosen is used to navigate around our demo web application. Keep in mind that because the treeTable supports hierarchical navigation, the model itself must be hierarchical. Therefore, we can simply reuse the tree model but we could not use any one of our table models. So the prepare method to setup the model looks like this:

public Map<String, Object> prepareTreeTableDialogMap() { Map<Str�ng,Object> map = new HashMap<Str�ng, Object>();

map.put("treeTableModel", controllerTree.getTree());

return map; }

Therefore, we reference our tree controller and take its model for our treeTable. The following screenshot shows the resulting treeTable in its collapsed state:

Adding major table capabilitiesWe now go ahead and include all the supported features we know from the table component. Actually, most of the table component features are supported:

<tr:treeTable id="testTreeTable" value="#{pageFlowScope.treeTableModel}" var="node" rowSelection="single" initiallyExpanded="true" bandingInterval="1" banding="row" horizontalGridVisible="true"

Page 210: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 9

[ 197 ]

verticalGridVisible="true" partialTriggers="::formContent: searchButton" rows="5">

We see that we can reuse many of the attributes of the table component—rowSelection, bandingInterval, banding, horizontalGridVisible, verticalGridVisible, and rows (and of course partialTriggers, but this is a part of most of the Trinidad components).

<f:facet name="actions"> <tr:commandButton id="treeTableSelectButton" autoSubmit="true" text="Submit Sel." act�on="#{controllerInteract�on.treeTableSelect}" />

</f:facet>

Again, we can even reuse some facets such as the actions facet we can see here. Next, we can see the new facets pertinent to the treeTable component:

<f:facet name="nodeStamp"> <tr:column headerText="Name"> <tr:outputText value="#{node.label}"/> </tr:column> </f:facet> <f:facet name="pathStamp">

<tr:outputText value="#{node.label}"/> </f:facet>

The tag concludes with the columns to be shown in our treeTable that is once again entirely analogous to the table component:

<tr:column headerText="Include" > <tr:outputText value="#{node.include}"/> </tr:column> <tr:column headerText="Method"> <tr:outputText value="#{node.prepareMethodName}"/> </tr:column> <tr:column headerText="Dialog" > <tr:selectBooleanCheckbox value="#{node.d�alog}" d�sabled="true"/>

</tr:column> <tr:column headerText="Content"> <tr:selectBooleanCheckbox value="#{node.content}" disabled="true"/> </tr:column></tr:treeTable>

Page 211: Apache Myfaces Trinidad 1.2 A Practical Guide (November

The table and treeTable Components

[ 198 ]

Additionally, there is a new facet called pathStamp that allows the selection of a focus on the view of the tree model. By clicking on a focus icon of a user-chosen row, the whole tree model is shown in a sub view that starts with the user-chosen row and with a display of the current train at the top example 'ch.2/ ch.2.1/ ch.2.1.2'. The user can then, at any time, jump up the hierarchy by clicking on the specific train item, for instance 'ch.2.1'.

Furthermore, we have added the component selectBooleanCheckbox (disabled, so just for pure display) which is handy when it comes to display Boolean data which is given in this case for two properties.

No support is given for the following features:

The table detail facet is not supported because the hierarchical navigation can be used to navigate to detail dataThe selection of a node is not provided with a method getSelectedRowData but requires an index-based approach due to the method getSelectedRowKeys being used instead

So the action event listener for the selection of a node must be adapted as follows:

pr�vate TreeNode f�ndSelectedNode(RowKeySet select�on, TreeNode tree)

{ Iterator<Integer> it = ((List<Integer>)selection.iterator(). next()).iterator(); �t.next();

while (it.hasNext()) tree = tree.getSuccessors().get(((Integer)�t.next()). �ntValue());

return tree;}

It can be seen that we traverse the tree according to the path indicated by the RowKeySet selection. Now for the main selection method, we access the tree table and ask for its selected row keys which we pass to the above helper find method called findSelectedNode:

public void treeTableSelect(){ UIXTreeTable treeTable = (UIXTreeTable)navi.getFacesContext(). getViewRoot().findComponent("formContent:testTreeTable"); RowKeySet select�on = treeTable.getSelectedRowKeys();

TreeNode node = f�ndSelectedNode(select�on, (TreeNode)

Page 212: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 9

[ 199 ]

((ControllerTree)treeTable.getAttributes(). get("value")).getTree().getWrappedData()); navi.getTrinidadContext().getPageFlowScope().put("selection", node.getLabel());}

We can see that helper find method is necessary to locate the selected node because the getSelectedRowKeys just returns a list that contains the path to the selected node in an array-index-based representation. Therefore, in the helper method we traverse the tree down to the selected node and return it. As the tree already points to its root node, we can skip the first zero index that explains the initial next operation.

Finally, the resulting node is saved in the pageFlowScope so it may also be additionally displayed on the page:

<tr:outputText partialTriggers="testTreeTable:treeTableSelectButton" value="#{pageFlowScope.selection}" />

The following screenshot shows the treeTable component in one of its expanded states:

Page 213: Apache Myfaces Trinidad 1.2 A Practical Guide (November

The table and treeTable Components

[ 200 ]

SummaryWe have seen how the table component is used and how its special features can be applied. Furthermore, we have learned how to encapsulate the table component by the use of JSF binding and thus, reduce the XHTML markup to a single line. We have also taken a look at the treeTable component that shares quite a bit with the table component, but adds further features to support hierarchical data.

Page 214: Apache Myfaces Trinidad 1.2 A Practical Guide (November

The Chart ComponentThis chapter deals with Trinidad's chart component and shows its application. The chart component allows the visualization of statistical data in a variety of graphical representations. With this flexibility in hand, the developers are able to visualize information that otherwise would remain hidden in raw statistical data. Furthermore, the developers are able to competently setup representation parameters, therefore, effectively achieving the intended representation focus and thus graphically materialize the hidden information in an adequate way. Typical areas of application include pharmaceutical data analysis, data warehousing, bank credit scoring, and also various types of controlling and any other area where dispositive data is generated.

We shall cover the following topics in this chapter:

The various chart types supported by Trinidad and their inter-relationsThe model side and how to create the models for the various chart typesThe setup of the chart component's parameters and chart-specific recommendations

Where the chart component is and what it supports Along with table, tree, and treeTable, the package org.apache.myfaces.trinidad.component offers the chart component—another big component from the core.data subpackage. As model, we find ChartModel to be an abstract model that is located in the core.model subpackage.

The chart component applies SVG and is compatible with browsers such as Firefox, Internet Explorer (Version 6 and above, using the Adobe SVG plugin), and Opera 9+.

Page 215: Apache Myfaces Trinidad 1.2 A Practical Guide (November

The Chart Component

[ 202 ]

The chart component is not just a component devised for a single chart. It supports a wide range of chart types, which is listed as follows:

bar charts (verticalBar, horizontalBar, stackedVerticalBar, and stackedHorizontalBar)pie charts (pie is its only type)area charts (area and stackedArea)line charts (line, barLine, and XYLine)scatter plot charts (scatterPlot is its only type)radar charts (radar and radarArea)funnel charts (funnel is its only type)gauge charts (circularGauge and semiCircularGauge)

Bar chartsThe bar chart includes a couple of types that are all variations of the most basic one in this type group, the verticalBar type. It is actually the classical bar chart that applies vertical bars horizontally grouped on the x-axis of a Cartesian coordinate system with each group made up of a series of values that are shown vertically on the y-axis. The effect is a clear graphical view of raw data that focuses on the comparison of the y-axis values along the groups and series. This type also exists as horizontalBar. Here the horizontal analog is visually turned around so that each bar now grows from the y-axis instead while the peak values are defined on the x-axis. Furthermore, there are stacked variations stated as follows:

stackedVerticalBar: This type is a refinement of the verticalBar type where each series is represented within one bar as part of that bar stackedHorizontalBar: This type is analogous to above type and just shows the bars growing horizontally instead

Let us start with the simplest example. To get the chart component running, we take the most basic (probably the widest used) bar chart type. In this simplest, yet absolutely effective case, the XHTML is only a single short line. Because the chart type is a bar by default, no type attribute must be passed:

<tr:chart value="#{pageFlowScope.chartModel}" />

Page 216: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 10

[ 203 ]

The model is an extension of the abstract class:

public class SimpleChartModel extends ChartModel { @Override public List<String> getGroupLabels() { List<String> list = new ArrayList<String>(); list.add("2008"); list.add("2009"); return list; } @Override public List<String> getSeriesLabels() { List<String> list = new ArrayList<String>(); list.add("Debts growth"); return list; } @Override public List<List<Double>> getYValues() { List<List<Double>> list = new ArrayList<List<Double>>(); List<Double> doubles = new ArrayList<Double>(); doubles.add(3.0); list.add(doubles); List<Double> doubles2 = new ArrayList<Double>(); doubles2.add(4.5); list.add(doubles2); return list; } }

Minimally, the methods getGroupLabels and getSeriesLabels must each return a non-empty list; otherwise, either the entire chart is not displayed or it is displayed empty.

Regarding the tag attributes of chart, the component does not usually return any error or warning messages if attribute values do not match. Rather, the chart display becomes somehow distorted. For example, choosing a too low maxPrecision or avoiding it altogether while setting a rather high YmajorGridLineCount may lead to unexpected results such as repeated labeling of the grid line. Even the avoidance of maxPrecision and too low bar chart y-axis values may lead to a confusing chart display with a very indefinite graphical representation of the y-axis values. This can be fixed by adding a sufficient maxPrecision:

<tr:chart value="#{pageFlowScope.chartModel}" maxPrecision="4" />

Page 217: Apache Myfaces Trinidad 1.2 A Practical Guide (November

The Chart Component

[ 204 ]

In the following image, we can see a basic Trinidad bar chart:

As usual, the model is instantiated and transferred into the pageFlowScope to make it available to the chart component tag:

public Map<String, Object> prepareChartBarDialogMap() { Map<String,Object> map = new HashMap<String, Object>(); map.put("chartModel", new SimpleBarModel()); return map; }

The bar chart is also available in a horizontal version. Its type is horizontalBar and must be explicitly specified as attribute of the component's tag:

<tr:chart value="#{pageFlowScope.chartModel}" maxPrec�s�on="�" type="hor�zontalBar" />

Page 218: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 10

[ 205 ]

As expected, the resulting chart is the analog of its vertical brother, as shown in the following image:

Stacking the bar chartA refined variation of the bar chart is a graphical representation of its composition so that one may see the distinguished components that the bar is composed of, as shown in the following image:

Page 219: Apache Myfaces Trinidad 1.2 A Practical Guide (November

The Chart Component

[ 206 ]

If the stacked type indication is left out, the representation is given bar by bar according to each series, as shown in the following image:

The model must be slightly adapted to make sure a minimal y-axis value is kept because otherwise. Trinidad automatically chooses a minimal value according to the provided data that may yield undesired results, such as a bar that grows below the y-axis. So the following code includes the implementation of the getMinYValue method:

public class SimpleStackedBarModel extends ChartModel { @Override publ�c Double getM�nYValue()

{

return 0.0;

}

@Override public List<String> getGroupLabels() { List<String> list = new ArrayList<String>(); list.add("2008"); list.add("2009"); return list; } @Override public List<String> getSeriesLabels() {

Page 220: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 10

[ 207 ]

List<String> list = new ArrayList<String>(); list.add("Poll. China"); list.add("Poll. USA"); list.add("Poll. EU"); list.add("Poll. Others"); return list; } @Override public List<List<Double>> getYValues() { List<List<Double>> list = new ArrayList<List<Double>>(); List<Double> doubles = new ArrayList<Double>(); doubles.add(50.0); doubles.add(23.0); doubles.add(12.0); doubles.add(6.0); list.add(doubles); doubles = new ArrayList<Double>(); doubles.add(60.5); doubles.add(30.0); doubles.add(15.2); doubles.add(8.0); list.add(doubles); return list; } }

Moreover, the data volume has been increased a bit to show off the stacking feature.

Pie chartsThe pie charts are used for the display of data segmentation; for example, how in a poll the participants are divided across areas defined in the poll, such as political orientation.

Making use of the chart component to generate a pie diagram is practically as simple as the bar chart itself. The only addition you need to make is that the type attribute is required to specify the pie type:

<tr:chart value="#{pageFlowScope.chartModel}" type="pie" />

Page 221: Apache Myfaces Trinidad 1.2 A Practical Guide (November

The Chart Component

[ 208 ]

The pie model is simpler than the bar model because we only use one double array of numbers (as part of the outer one-element array to satisfy the model's chosen data structure) to define the pie segmentation:

public class SimplePieModel extends ChartModel { @Override public List<String> getGroupLabels() { List<String> list = new ArrayList<String>(); list.add("2009"); return list; } @Override public List<String> getSeriesLabels() { List<String> list = new ArrayList<String>(); list.add("Right-wing parties in Kasachstan"); list.add("Other parties"); return list; } @Override public List<List<Double>> getYValues() { List<List<Double>> list = new ArrayList<List<Double>>(); List<Double> doubles = new ArrayList<Double>(); doubles.add(70.0); doubles.add(30.0); list.add(doubles); return list; } }

The following image shows a basic Trinidad pie chart:

Page 222: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 10

[ 209 ]

The model is transferred into the pageFlowScope, for the chart component tag to be able to pick it up there:

public Map<String, Object> prepareChartPieDialogMap() { Map<String,Object> map = new HashMap<String, Object>(); map.put("chartModel", new S�mpleP�eModel()); return map; }

This preparation step is something that will also occur in an entirely analogous way for the other models. Only the put method call changes from preparation method to display of data segmentation.

Area chartsThe area chart type adds another focus to diagrams such as pie diagrams. Its primary focus lies on change over time, yet the representation of data segmentation as in pie diagrams remains as another focus. Data segmentation may be visualized either by defining several series or by using stackedArea, a chart type that acts as refinement of the area type showing the segmentation in a similar way as in the stacked refinements of the bar chart type.

This time, similar to bar chart types, the most minimal tag usage may not suffice to produce a proper diagram because the aim of this diagram type to reflect developmental aspects (typically growth) of statistical data demands differentiated data. Even if the data is differentiated, a lack of precision can still make the data look like it is too homogenous so no development is really traceable.

<tr:chart value="#{pageFlowScope.chartModel}" type="area" maxPrecision="4" />

Page 223: Apache Myfaces Trinidad 1.2 A Practical Guide (November

The Chart Component

[ 210 ]

Therefore, a valid workaround is used to increase the precision so data variation is noticeable, and thus graphically representable, as shown in the following image:

The same model as the one for the bar chart can be used—the area chart just shows the data from the growth perspective and so is very apt for the display of developments.

Analogously, the data (model) used in the stacked refinement of this chart the model for the stacked bar chart can be reused, as shown in the following image:

Page 224: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 10

[ 211 ]

Line chartsLine charts represent a chart type whose pivotal, and practically sole, focus is change over time. Trinidad additionally supports two chart refinements—barLine, which adds bar data to the line chart so that a superposition of verticalBar and line is realized, and XYLine, where x-axis data is used to position the y-axis data along the x-axis while neighboring points are connected to each other by a line.

The same model as the one for the bar chart may be used because the diagram has a focus on growth just like the area chart, but without a stress on the areas that are delimited by the y-axis curve.

Trinidad also supports a refinement of this chart and allows superposing a bar chart. As a consequence, we need a richer model that additionally includes bar chart model data:

public class SimpleBarLineModel extends ChartModel { @Override public List<String> getGroupLabels() { List<String> list = new ArrayList<String>(); list.add("2008"); list.add("2009"); return list; }

Page 225: Apache Myfaces Trinidad 1.2 A Practical Guide (November

The Chart Component

[ 212 ]

@Override public List<String> getSeriesLabels() { List<String> list = new ArrayList<String>(); list.add("Debts growth"); list.add("Pollution growth"); return list; } @Override public List<List<Double>> getYValues() { List<List<Double>> list = new ArrayList<List<Double>>(); List<Double> doubles = new ArrayList<Double>(); doubles.add(3.0);

doubles.add(�.0);

list.add(doubles); doubles = new ArrayList<Double>(); doubles.add(�.�);

doubles.add(�.0);

list.add(doubles); return list; } }

In the preceding code, the data pairs in each series. Therefore, both charts can be drawn and superposed, as shown in the following image:

Page 226: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 10

[ 213 ]

The line chart type has yet another two variations—XYLine and scatterPlot, which share the same model:

public class SimpleScatterPlotModel extends ChartModel { @Override public List<String> getGroupLabels() { List<String> list = new ArrayList<String>(); list.add("2008"); list.add("2009"); return list; } @Override public List<String> getSeriesLabels() { List<String> list = new ArrayList<String>(); list.add("Debts growth"); return list; } @Override public List<List<Double>> getYValues() { List<List<Double>> list = new ArrayList<List<Double>>(); List<Double> doubles = new ArrayList<Double>(); doubles.add(3.0); list.add(doubles); doubles = new ArrayList<Double>(); doubles.add(4.5); list.add(doubles); return list; } @Override publ�c L�st<L�st<Double>> getXValues() { L�st<L�st<Double>> l�st = new ArrayL�st<L�st<Double>>(); L�st<Double> doubles = new ArrayL�st<Double>(); doubles.add(1.0); l�st.add(doubles); doubles = new ArrayL�st<Double>(); doubles.add(10.�); l�st.add(doubles); return l�st; } }

Page 227: Apache Myfaces Trinidad 1.2 A Practical Guide (November

The Chart Component

[ 214 ]

The specific aspect of this model is its additional method named getXValues. It allows you to control the points of the x-axis (x1,x2 and so on) that are bound to the y-axis values (y1,y2 and so on); therefore, only those ordered pairs ((x1,y1),(x2,y2), and so on) are taken for the graphical representation, as shown in the following image:

ScatterPlot chartsThe scatterPlot chart type is almost identical to the XYLine except that it leaves the points unconnected so lots of points may be shown in the diagram making it is possible to realize representations that depict clouds of points.

More concretely, the scatter plot chart is a diagram that displays all the 2-dimensional points provided in the methods getYValues and getXValues. Therefore, in addition to the y-axis values, the model must also provide x-axis values. In the graphical representation, it differs from the XYLine chart type insofar as no line is drawn between the provided data points, as shown in the following diagram:

Page 228: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 10

[ 215 ]

Radar chartsRadar charts are a chart type that focuses on comparison and serves very well to show degrees of completion and quality such as fulfillment, achievement, or level. Its refinement, radarArea, is available to set an emphasis on the area that is actually covered by the statistical data.

The radar chart is also known as spider diagram since it looks a bit like a spider's web—the points at its extremes being the spots where the web is fixed. It serves well when it comes to show the status of something such as a project in its various dimensions at one glance.

The model for this chart type is easy to follow because data values must only be provided for the dimensions (in getGroupLabels) that are measured; see the getYValues method in the following model code:

public class SimpleRadarModel extends ChartModel { @Override publ�c L�st<Str�ng> getGroupLabels() { List<String> list = new ArrayList<String>(); list.add("Maintainability"); list.add("Modularity"); list.add("Functionality"); list.add("Performance"); list.add("Deployability"); return list;

Page 229: Apache Myfaces Trinidad 1.2 A Practical Guide (November

The Chart Component

[ 216 ]

} @Override public List<String> getSeriesLabels() { List<String> list = new ArrayList<String>(); list.add("Software quality management"); return list; } @Override publ�c L�st<L�st<Double>> getYValues() { List<List<Double>> list = new ArrayList<List<Double>>(); List<Double> doubles = new ArrayList<Double>(); doubles.add(60.0); list.add(doubles); doubles = new ArrayList<Double>(); doubles.add(50.0); list.add(doubles); doubles = new ArrayList<Double>(); doubles.add(90.0); list.add(doubles); doubles = new ArrayList<Double>(); doubles.add(80.0); list.add(doubles); doubles = new ArrayList<Double>(); doubles.add(52.0); list.add(doubles); return list; } }

The following image shows a basic Trinidad radar chart:

Page 230: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 10

[ 217 ]

Next, we have a look at the image of a basic Trinidad radar area chart:

As we can already see in the foregoing charts, it is possible to display several series in one chart. Thus, the model must be richer and also include several data series. In the case of radar area chart, the display is then filled with as many webs as there are series in the data, which of course holds for both the chart types—radar and radar area. So, our example radar model just needs a second series to achieve two webs in one diagram; to achieve this, we enrich the methods getSeriesLabels and getYValues to include a second series:

public class SimpleRadarAreaModel extends ChartModel { @Override public List<String> getGroupLabels() { List<String> list = new ArrayList<String>(); list.add("Maintainability"); list.add("Modularity"); list.add("Functionality"); list.add("Performance"); list.add("Deployability"); return list; } @Override public List<String> getSeriesLabels() { List<String> list = new ArrayList<String>(); l�st.add("Software QM v.1.0"); l�st.add("Software QM v.�.0"); return list;

Page 231: Apache Myfaces Trinidad 1.2 A Practical Guide (November

The Chart Component

[ 218 ]

} @Override public List<List<Double>> getYValues() { List<List<Double>> list = new ArrayList<List<Double>>(); List<Double> doubles = new ArrayList<Double>(); doubles.add(�0.0); doubles.add(�0.0); list.add(doubles); doubles = new ArrayList<Double>(); doubles.add(�0.0); doubles.add(�0.0); list.add(doubles); doubles = new ArrayList<Double>(); doubles.add(�0.0); doubles.add(80.0); list.add(doubles); doubles = new ArrayList<Double>(); doubles.add(80.0); doubles.add(��.0); list.add(doubles); doubles = new ArrayList<Double>(); doubles.add(��.0); doubles.add(��.0); list.add(doubles); return list; } }

In the following image, we can see a basic Trinidad radar area chart with two series:

Page 232: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 10

[ 219 ]

Funnel chartsThe funnel chart is an alternative to the pie representation. Instead of a pie graphic, a funnel-like looking graphic is used. Their models are identical; hence the code for the pie model can be reused. The following image shows a funnel chart:

Gauge chartsGauge charts are chart types that serve to represent singular data, that is, single peaks of a range that may also be shown in a slight graphical variation called semiCircularGauge. Whereas, circularGauge uses a full circle whereon the peak value is placed; typical usage involves risk data evaluation.

Basically, it deals with a tachometer representation of a peak value, either in full-circle view (rather more nostalgic looking) or in a half-moon form (looks rather modern). A basic Trinidad gauge chart is shown in the following image:

Page 233: Apache Myfaces Trinidad 1.2 A Practical Guide (November

The Chart Component

[ 220 ]

The following image shows a half moon form Trinidad gauge chart:

Obviously, the models are quite simple; as we shall see in the following code example:

public class SimpleGaugeModel extends ChartModel { @Override publ�c Double getMaxYValue() { return 50.0; } @Override publ�c Double getM�nYValue() { return 0.0; } @Override public List<String> getGroupLabels() { List<String> list = new ArrayList<String>(); list.add("Risk value"); return list; } @Override public List<String> getSeriesLabels() { List<String> list = new ArrayList<String>(); return list; } @Override publ�c L�st<L�st<Double>> getYValues()

Page 234: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 10

[ 221 ]

{ List<List<Double>> list = new ArrayList<List<Double>>(); List<Double> doubles = new ArrayList<Double>(); doubles.add(30.0); list.add(doubles); return list; } }

Essentially, three methods are the characteristics of this model:

getYValues: This is used to set the actual peak value (in the preceding example, it's 30)getMaxYValue: This is used to set the gauge's top value (in the preceding example, it's 50)getMinYValue: This is used to set the gauge's bottom value (in the preceding example, it's 0)

SummaryWe have seen that Trinidad's charting features offer a broad spectrum, ranging from simple bar charts to refined chart types such as radar areas.

All of this is accomplished by using the chart tag that has a type attribute to specify the desired chart type—bar charts such as the verticalBar, horizontalBar, stackedVerticalBar, and stackedHorizontalBar types. The pie chart, with its only type pie, serves to display data segmentation.

The area charts, area and stackedArea, also aim at data segmentation. However, it combines this with a focus on change over time—which, in contrast, is the one and only purpose of the line charts line, barLine, and XYLine.

As the name suggests, XYLine displays a line specified by its x and y coordinates. The scatter plot chart type with its only type scatterPlot is practically identical, except for leaving the specified points unconnected. The radar chart types radar and radarArea focus on the display of comparable data.

The funnel chart, with its only type funnel, is an alternative to the pie representation which uses a funnel graphic instead of a pie image. Finally, gauge charts serve to represent singular data.

In the upcoming chapter, we will deal with the development of a wizard which, in contrast to the refined chart support of Trinidad, focuses more on one's own developer resources. We will profit from Facelets and so it will serve as another example on how to create a component without having to build a fully fledged JSF tag.

Page 235: Apache Myfaces Trinidad 1.2 A Practical Guide (November
Page 236: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a WizardThis chapter deals with Trinidad's components to implement a wizard and show their application. Contrary to the usual approach of profiting from specific components that Trinidad has to offer for implementing a wizard, we are caught by reality and have to workaround an old well-known Facelet compatibility bug (see TRINIDAD-26 in the Trinidad JIRA). Moreover, we will develop a fully working Facelet alternative that resembles Trinidad's dysfunctional singleStepButtonBar component.

The following topics will be covered in this chapter:

How to define an abstract wizard modelHow to create specific wizard instancesHow to apply the wizard Facelet tag on the XHTML side

Defining an abstract wizard modelWe solve the problem by using Trinidad's own design approach (for instance, Chapter 10, The Chart Component, shows this technique with Trinidad's ChartModel class) and define an abstract model for arbitrary wizard objects that contain the actual wizard navigation data themselves.

The properties of the abstract wizard modelThe abstract wizard class is defined as an object that contains the properties maxSteps to keep the maximum number of allowed steps, selectedStepIndex to keep the current step, and step which contains the actual step information:

import java.util.List;import javax.faces.event.ActionEvent;import com.test.TrinidadSeamidadApplication.TreeNode;

/**

Page 237: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a Wizard

[ 224 ]

* This is an abstract model implemented by specific wizard objects * with specific wizard data steps */public abstract class WizardModel {

/** * the maximum number of steps that the wizard navigates along */ private short maxSteps;

/** * the currently shown wizard step */ pr�vate short selectedStepIndex = 0;

/** * keeps all the steps that the wizard works through */ protected L�st<TreeNode> step;

Constructors of the abstract wizardWe provide a couple of special features for the construction of a wizard object. Therefore, the developer may either use her or his own initialization by overriding initializeModel or by using the parameterized constructor:

/** * Standard Constructor - NOTE: * makes only sense if step is initialized, thus initializeModel * is called */ public WizardModel() { �n�t�al�zeModel(); }

/** * initialize the steps and their upper limit which allows to keep * the code of the model data inside the specific model of this * abstract class */ publ�c abstract vo�d �n�t�al�zeModel();

/** * the usual alternative to using the parameterless constructor;

Page 238: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 11

[ 225 ]

* we can apply this constructor here which expects initialized * data as in initializeModel() * * @param maxSteps * @param step */ public WizardModel(short maxSteps, List<TreeNode> step) { super(); this.maxSteps = maxSteps; this.step = step; }

Providing the current step, action, and actionListener methodsThe following method is crucial to the wizard functionality as it return the actual step object that is a TreeNode-as it contains the panel-related information of the panel contents to be shown:

publ�c TreeNode getSelectedStep() { return step.get(getSelectedStepIndex()); }

The upcoming couple of method pairs deal with the provision of action and action listener methods to allow the developer to do wizard-specific activities following a user click on the next or back button:

/** * listens to a user click on the back wizard step button */ publ�c abstract vo�d backStepL�stener(Act�onEvent event);

/** * listens to a user click on the next wizard step button */ publ�c abstract vo�d nextStepL�stener(Act�onEvent event);

/** * acts on a user click on the next wizard step button */ publ�c abstract vo�d nextStepAct�on();

/** * acts on a user click on the back wizard step button */ publ�c abstract vo�d backStepAct�on();

Page 239: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a Wizard

[ 226 ]

Providing control for the number of wizard stepsThe abstract wizard class continues with the control of the maximum number of allowed steps:

/** * Getter of the property <tt>maxSteps</tt> * @return Returns the maxSteps. */ public short getMaxSteps() { System.out.println("** getMaxSteps **"); return maxSteps; }

/** * Setter of the property <tt>maxSteps</tt> * @param maxSteps The maxSteps to set. */ public void setMaxSteps(short maxSteps) { System.out.println("** setMaxSteps **"); this.maxSteps = maxSteps; }

Providing control for the current step index The abstracted wizard then provides the methods to control the selected step index:

/** * Getter of the property <tt>selectedStep</tt> * @return Returns the selectedStep. */ publ�c short getSelectedStepIndex() { return selectedStepIndex; }

/** * Setter of the property <tt>selectedStep</tt> * @param selectedStep The selectedStep to set. */ publ�c vo�d setSelectedStepIndex(short selectedStep) { this.selectedStepIndex = selectedStep; }

Page 240: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 11

[ 227 ]

Providing step incrementation and decrementationThe abstract wizard closes with the implementation of the incrementation and decrementation methods where boundaries are checked to ensure a permitted increase or decrease:

/** * moves on to the next step */ publ�c vo�d �ncrementStep() { if(selectedStepIndex<getMaxSteps()) selectedStepIndex++; }

/** * moves back to the last step (the step before the current step) */ publ�c vo�d decrementStep() { if(selectedStepIndex>0) selectedStepIndex--; }}

Abstract class design aspectsIt makes sense to design this as an abstract class particularly because it is quite clear that some concrete functionality can be provided whilst providing enough liberty for the developer to accommodate her or his own specific wizard behavior. Thus, the following concrete method implementations are provided:

incrementStep and decrementStep: They allow moving forward and backward in the series of wizard steps which is the main navigation to be found in a wizard.setSelectedStepIndex and getSelectedStepIndex: They allows moving to a specific step further away from a neighboring step. Note that we distinguish between the step index and the step itself which is an object that contains all the data (or references to such) to produce a step.getSelectedStep: This is provided to get the respective step based on the current value of the selected step index.

Page 241: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a Wizard

[ 228 ]

Then there are a couple of abstract methods that the developer is supposed to implement concretely in her or his own wizard extension:

nextStepAction or backStepAction: This would suffice to implement the nextStepAction to enable the wizard’s moving capability

nextStepListener or backStepListener: This would suffice to implement the nextStepListener to enable the wizard’s moving capability

Only one implementation of each couple is really required. To enable the wizard we need specific wizard step data that contains all the wizard needs to know to display and work through each step; two alternatives are offered:

Using the default empty constructor requires the concrete implementation of the initializeModel method where the list of step data is supposed to be created (for clarity we prefer this method in the following section)Using the parameterized constructor requires passing the list of step data

Defining the concrete wizardNow, we are ready to define specific wizard instances. As an example, we implement one wizard that is used inside the preparation controller which allows moving through a couple of chart views.

Implementing the wizard's action listeners The class definition starts with the implementation of the step listeners in preference to action method, which therefore remains empty:

/** * This is a wizard to implement a sort of chart report to page * through in wizard-like way */ public class Wizard extends WizardModel {

@Override public void nextStepListener(ActionEvent event) { �ncrementStep(); navigate(event); }

public void backStepListener(ActionEvent event) { decrementStep();

Page 242: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 11

[ 229 ]

navigate(event); }

@Override public void backStepAction() { // TODO Auto-generated method stub }

@Override public void nextStepAction() { // TODO Auto-generated method stub }

Implementing the wizard's navigationNext follows the implementation of the navigation which consists of fetching the selected step, and respectively setting the panel's content:

/** * navigate to the selected step * @param event */ private void navigate(ActionEvent event) { ControllerPanel controllerPanel =

(ControllerPanel)Contexts.lookupInStatefulContexts ("controllerPanel"); TreeNode node = getSelectedStep(); PanelModel panel = controllerPanel.getContentPanel(); panel.setInclude(node.getInclude()); panel.setLabel(node.getLabel()); Navigator navi =

(Navigator)Contexts.lookupInStatefulContexts("navi"); nav�.nav�gate(node.�sD�alog(), node.getPrepareMethodName(), event); }

Page 243: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a Wizard

[ 230 ]

Implementing a step objectA step object here actually is a TreeNode object. This is something quite implementation-specific because we profit by reuse. In other, more complex designs, this would be a larger step object on its own. However, for our panel-based control it suffices perfectly and is easy to follow:

/** * creates a TreeNode instance based on the provided parameters * * @param include the panel-specific XHTML code to be * included, i.e. not a full page.. * @param nodeLabel the panel label to be displayed * @param prepareMethodName the prepare method to be called * before the panel is refreshed * @return the resulting step data object, actually we profit * from reusing TreeNode */ private TreeNode createNode(String include, String nodeLabel, String... prepareMethodName) { TreeNode node = new TreeNode(include,nodeLabel); // show them all in just one Trinidad dialog i.e. the // one created when clicking on the tree item :) // so we do not need to create any more node.setDialog(false); if (prepareMethodName.length>0) node.setPrepareMethodName(prepareMethodName[0]); return node; }

Initializing a wizard instanceThe class closes with the method to initialize a wizard instance:

@Override publ�c vo�d �n�t�al�zeModel() { short maxSteps = 5; setMaxSteps(maxSteps); //initialize the array list that is stepped through step = new ArrayL�st<TreeNode>();

Page 244: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 11

[ 231 ]

step.add(createNode("ch.II-5/radar", "Chapter II-5 Radar", "prepareChartRadarD�alogMap")); step.add(createNode("ch.II-5/radarArea", "Chapter II-5 Radar Area", "prepareChartRadarDialogMap")); step.add(createNode("ch.II-5/radarArea2", "Chapter II-5 Radar Area 2", "prepareChartRadarAreaDialogMap")); step.add(createNode("ch.II-5/funnel", "Chapter II-5 Funnel", "prepareChartPieDialogMap")); step.add(createNode("ch.II-5/circularGauge", "Chapter II-5 Circular Gauge", "prepareChartGaugeDialogMap")); step.add(createNode("ch.II-5/semiCircularGauge", "Chapter II-5 Semi-circular Gauge", "prepareChartGaugeDialogMap")); } }}

This is where the actual steps are added. In this case, as already mentioned, we define a series of charts to step through.

The wizard's application inside the preparation controllerIn the preparation controller, we introduce another preparation method that takes care of the wizard construction and returning it wrapped inside a map ready to be passed to a Trinidad dialog:

/** * @return a map containing all the data for the page flow to be used to access the wizard */ public Map<String,Object> prepareWizard() { Wizard wizardModel = new Wizard(); Map<String,Object> map = new HashMap<String, Object>(); map.put("w�zard", w�zardModel);

return map; }

Page 245: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a Wizard

[ 232 ]

Wizard implementation design aspectsAs a result, we can see that implementing this wizard by extension results in a quite compact and maintainable wizard instance with the following interesting features:

The navigation is entirely delegated to the navigation controller that implies a generalizing refactoring of the navigation method we saw in the tree controller. Thus, both the wizard and the tree controller delegate navigation to the navigation controller (its dialog and PPR features will be discussed in the following chapter) so the tree controller's delegating navigate method is simplified to:

public void navigate(ActionEvent event) { Map<String,Object> map = event.getComponent().getAttributes(); boolean isContent = ((Boolean)map.get("isContent")). booleanValue(); PanelModel panel = isContent? controllerPanel. getContentPanel(): controllerPanel.getDescriptionPanel(); panel.setInclude((String)map.get("include")); panel.setLabel((String)map.get("label")); Str�ng methodName = (Str�ng)map.get("prepareMethodName");

boolean isDialog = ((Boolean)map.get("isDialog")). booleanValue(); nav�.nav�gate(�sD�alog, methodName, event);

}

Another interesting feature of the preceding delegating navigation method is that it now also looks for prepareMethodName—a new attribute that allows specifying the preparation method required to setup the data objects is required for the respective step. It is entirely analogous to the chart object preparation we got to know in the previous chapter.The initializeModel attribute is basically implemented in the same way as the initialization of the tree model because we work with the same basic unit, the TreeNode, as it contains everything that needs to be known to produce a step. In addition, setMaxSteps must be used to set the number of steps that the wizard is expected to navigate through.The initializeModel attribute also applies a more general version of TreeNode that supports storing the name of the respective preparation method (refer to Chapter 12, Dialogs—Pop Up Your Web Application, for a complete discussion as this is also connected with the Trinidad dialog feature in detail).

Page 246: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 11

[ 233 ]

The action listeners apply the abstract model's increment and decrement methods and then delegate to the same navigation.The tree controller is generalized to support the preparation methods (refer to Chapter 12, Dialogs—Pop Up Your Web Application, for a complete discussion in connection with the Trinidad dialog feature).

On the whole, notice how flexible the abstract model's API allows working with the wizard:

There must be no fixed sequence of action that must be followed. The abstract model just provides basic methods that may be called as convenience calls, for example, increment and decrement.The following wizard example gives a hint on what other wizard instances of the same abstract model would possibly include, for instance fuller fledged action listeners that would prepare objects and call validation logic before moving on to another wizard step.

Page 247: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a Wizard

[ 234 ]

We can see the derivation of a wizard model instance that uses panels by means of a panel model and a panel controller, tree nodes as wizard step objects, and the navigator to apply respective panel navigation.

Defining the XHTML side—the wizard's faceBut how do we call and use the above wizard object? Well, we just need our own singleStepButtonBar tag. Thanks to Facelets, this is easily accomplished by means of the definition of a new Facelet composition component of the same name:

<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:trh="http://myfaces.apache.org/trinidad/html" xmlns:tr="http://myfaces.apache.org/trinidad" xmlns:c="http://java.sun.com/jstl/core" xmlns:s="http://jboss.com/products/seam/taglib">

<!-- this facelet expects the wizard model in the pageFlowScope its id being 'wizard' --> <!-- if model is provided then it uses this one instead --> <c:choose> <c:when test="#{not empty model}"> <c:set var="value" value="#{model}" /> </c:when> <c:otherwise> <c:set var="value" value="#{pageFlowScope.w�zard}" /> </c:otherwise> </c:choose> <!-- the user can switch between two kinds of display, a simple one that only shows the next and back button and the one with an indication of the current position --> <c:if test="#{empty simpleDisplay or not simpleDisplay}"> <c:set var="s�mpleD�splay" value="false" /> </c:if>

<c:set var="msgLabelNext" value="#{messages['msgWizNext']}" /> <c:set var="msgLabelBack" value="#{messages['msgWizBack']}" /> <c:set var="msgLabelStep" value="#{messages['msgWizStep']}" /> <c:set var="msgLabelOf" value="#{messages['msgWizOf']}" />

Page 248: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 11

[ 235 ]

<tr:panelButtonBar hal�gn="center"> <c:choose> <c:when test="#{not empty useBackStepListener and useBackStepListener and not empty useBackStepAction and useBackStepAction}"> <tr:commandButton id="singleStepButtonBack" text="#{msgLabelBack}" act�onL�stener="#{value.backStepL�stener}" act�on="#{value.backStepAct�on}" /> </c:when> <c:otherwise> <c:choose> <c:when test="#{(empty useBackStepListener or not useBackStepListener) and (not empty useBackStepAction and useBackStepAction)}"> <tr:commandButton id="singleStepButtonBack" text="#{msgLabelBack}" act�on="#{value.backStepAct�on}" /> </c:when> <c:otherwise> <tr:commandButton id="singleStepButtonBack" text="#{msgLabelBack}}" act�onL�stener="#{value.backStepL�stener}" /> </c:otherwise> </c:choose> </c:otherwise> </c:choose> <c:�f test="#{not s�mpleD�splay}"> <tr:outputText value="#{msgLabelStep}" /> <tr:outputText value="#{value.selectedStepIndex}" /> <tr:outputText value="#{msgLabelOf}" /> <tr:outputText value="#{value.maxSteps}" /> </c:if> <c:choose> <c:when test="#{not empty useNextStepListener and useNextStepListener and not empty useNextStepAction and useNextStepAction}"> <tr:commandButton id="singleStepButtonNext" text="#{msgLabelNext}" act�onL�stener="#{value.nextStepL�stener}" act�on="#{value.nextStepAct�on}" /> </c:when> <c:otherwise> <c:choose>

Page 249: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Building a Wizard

[ 236 ]

<c:when test="#{(empty useNextStepListener or not useNextStepListener) and (not empty useNextStepAction and useNextStepAction)}"> <tr:commandButton id="singleStepButtonNext" text="#{msgLabelNext}" act�on="#{value.nextStepAct�on}" />

</c:when> <c:otherwise> <tr:commandButton id="singleStepButtonNext" text="#{msgLabelNext}" act�onL�stener="#{value.nextStepL�stener}" />

</c:otherwise> </c:choose> </c:otherwise> </c:choose> </tr:panelButtonBar></ui:composition>

This composition component is able to offer a tag-based interface to the developer that is somewhat similar to Trinidad's original singleStepButtonBar. However, it intentionally differs in the following respects:

It either expects a model called wizard in the pageFlowScope (in this case, no tag attribute is needed) or the model must be passed as value of the tag attribute modelThe model must be an extension of our abstract WizardModel classAdditionally, it has a Boolean attribute simpleDisplay that if true, reduces the display of this component to next and back buttons but without any indication as to the current wizard step positionIt is always shown despite a possibly excluding state of steps or of the current step position (which is easier to handle to implement more stable-looking views)It applies Trinidad's panelButtonBar and uses its halign attribute to show the bar on the right-hand side (obviously, this could easily be generalized by passing a further alignment attribute)It expects its control mechanisms implemented either by a couple of listeners or actions or even both, which explains the applied choose case differentiation

Page 250: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 11

[ 237 ]

Therefore, in case of above specific wizard instance, an application of this tag would simply look like as follows:

<face:singleStepButtonBar useNextStepListener="true" useBackStepListener="true" />

And the wizard's face is as simple, and yet as effective, as the Trinidad singleStepButtonBar original, as shown in the following image:

SummaryWe have learned a way to develop a wizard as an alternative to Trinidad's built-in wizard support. Unfortunately, it is not fully compatible with Facelets due to a Trinidad bug (TRINIDAD-26 in the Trinidad JIRA). Thanks to Facelets, we have been able to deal with the situation in an elegant way. First, we developed an abstract wizard model, then created a specific instance, and finally applied it as model for a self-built wizard Facelet tag.

In the upcoming chapter, we are going to see how to use Trinidad's dialog framework to create pop up windows. Among other things, we will extend the presented wizard with pop-up support.

Page 251: Apache Myfaces Trinidad 1.2 A Practical Guide (November
Page 252: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Dialogs: Pop-Up Your Web Application!

This chapter discusses Trinidad's pop-up window techniques. Seam conversations are revisited to address Trinidad's and Seam's specific necessities for pop-up dialogs. The web application is enhanced by a couple of pop-up windows including pop-up support by means of a wizard.

There are three ways to use Trinidad dialogs in one's web application:

1. Trinidad dialogs as intrinsic technique to build a web application around.2. Trinidad dialogs as a specific means to implement light-weight or browser

pop-up windows as part of a JSF application.3. Trinidad dialogs as a specific means to implement parts of a JSF application

such as wizards; similar to the foregoing usage, the application always returns to non-dialog navigation.

The latter two are actually specific instances of the same usage—using a Trinidad dialog as a unit that is separated from the rest of the web application that is web page based. The first usage is the most consequent departure from the traditional web application in that no page based navigation controlled and declared by a pages navigation file is applied.

Page 253: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Dialogs: Pop-Up Your Web Application!

[ 240 ]

Looking at this from a more detailed, technical programming perspective, the possible usage specializes into various cases, such as follows:

Generally, opening a Trinidad dialog instead of generally using basic JSF page navigation, possibly including the closure of a foregoing dialog (that is, if there is one)Indirectly opening a Trinidad dialog in consequence of a click on a link (for example, the selection of a tree menu item by means of a Trinidad commandLink component) or a click on a button (Trinidad commandButton component)Indirectly opening a Trinidad dialog by using the Trinidad Dialog framework APIDirectly opening a Trinidad dialog by using the Trinidad components supported by the Trinidad dialog framework (typically, commandLink and commandButton)

In our sample application, we want to come close to the first way of using Trinidad dialogs. Moreover, to illustrate pop-up dialogs as well as dialogs on the main browser window, we will make our application so flexible as to allow any link to a dialog to be easily switched from a main browser window dialog to a pop-up dialog. The following will be covered:

Full API-wise control of dialogs as the most powerful means to deal with dialogsEncapsulation of the dialog framework as the basis for a uniform access to Trinidad dialog controlConsideration of the panel-based control to ensure that dialogs including pop-up dialogs are basically using the same uniform panel-based design

Using the right scope: Seam or only Trinidad Fortunately, this is nowadays a question of choice in design, because both ways are equally justified. Both ways have their specific advantages and shortcomings. We owe this liberty in choice to open source work. As a result, the integration of Trinidad's dialogs into the Seam framework is now a routine. It can be achieved in the following manner:

public class SeamPageFlowScopeProviderImpl extends PageFlowScopeProvider {

Page 254: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 12

[ 241 ]

private PageFlowScopeProvider pageFlowScopeProvider = PageFlowScopeProviderImpl.sharedInstance();

public SeamPageFlowScopeProviderImpl() { // TODO Auto-generated constructor stub }

@Override publ�c Str�ng encodeCurrentPageFlowScopeURL( FacesContext context,Str�ng url) { url = pageFlowScopeProvider.encodeCurrentPageFlowScopeURL( context, url); Str�ng conversat�onIdParameterName = Manager.�nstance().getConversat�onIdParameter(); Str�ng conversat�onId = Manager.�nstance(). getCurrentConversat�onId();

�f (conversat�onId!=null && conversat�onId.length()>0) url = EncoderUt�ls.appendURLArguments(url, new Str�ng[] { conversat�onIdParameterName, conversat�onId }); return url; }

@Override public Map<String, Object> getPageFlowScope(FacesContext context) { return pageFlowScopeProvider.getPageFlowScope(context); }

@Override public Map<String, Object> popPageFlowScope(FacesContext context, boolean discardScope) { return pageFlowScopeProvider.popPageFlowScope( context, discardScope); }

@Override public Map<String, Object> pushPageFlowScope(FacesContext context, boolean copyParent) { return pageFlowScopeProvider.pushPageFlowScope( context, copyParent); }}

As already mentioned in Chapter 5, Web Application Groundwork, it is not difficult to create this class. This is because there is actually only one method that is interesting, the rest has been generated for us—thanks to the IDE (for example, using Eclipse and choosing to implement the abstract class behind it). It extends Trinidad's abstract class PageFlowScopeProvider that allows modifying the URLs that are used in the course of Trinidad dialogs.

Page 255: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Dialogs: Pop-Up Your Web Application!

[ 242 ]

How the conversation is kept during a Trinidad dialogThe idea is quite simple—to let Seam know which conversation is going on during a Trinidad dialog we profit from Seam's ability to pick up the conversation from the URL. This is where Trinidad's PageFlowScopeProvider comes into play. By implementing it in a slightly modified version, which we have seen in the preceding section, we are able to insert the current conversation information into the dialog URLs. We overwrite the method encodeCurrentPageFlowScopeURL, and carry out the following steps there:

1. Fetch the current URL using Trinidad's encodeCurrentPageFlowScopeURL.2. Get the application-wide used ID for the conversations (for example,

cid—this may be setup in Seam's component.properties file).3. Fetch the current value of the conversation that is, usually a number

identifying the current long-running conversation.4. Append the parameter name or value pair to the current URL by using

Trinidad's appendURLArguments if there is a current long-running conversation.

5. Return this modified URL.

Now we can work as if we were on a simple JSF page, without any dialog—we can profit from Seam components in conversations, and all the other conversation state facilities provided by Seam such as bijections, injections, or outjections inside of conversations. Generally, it is advisable to stick to Seam because of its consistent conversation management. Yet the simpler page flow management provided by Trinidad has merits of its own because it is effectively integrated into the dialog mechanisms of dialog preparation and post-processing. As this is a book on Trinidad, we will stress this point more than Seam and we will see in the upcoming sections how Trinidad's pageFlowScope can be a very effective alternative when it comes to using Trinidad dialogs.

Page 256: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 12

[ 243 ]

Defining a dialog-enabled navigation controlFor our convenience, we define a central controller for navigational processing of our sample application. The concrete advantages of this approach are striking:

Encapsulation of navigational functionality: Although the Trinidad framework is quite refined and powerful, it is also somewhat raw due to its general purpose design and so it does not hide much from the developer. This can be improved by focusing on the relevant functionality.Specific extended navigational functionality built on the Trinidad framework: It is not out of the box to implement the flexible sort of navigational behavior we have described in the foregoing; as a consequence, it makes sense to build it on top of Trinidad.

Thus, we create the following navigation controller. As usual we make it a Seam component:

@Name("navi")@Startup@Scope(ScopeType.SESSION)public class Navigator {

pr�vate short numberOfOpenedD�alogs = 0; private boolean popup = false; @In ControllerPreparation controllerPrepare;

This Seam component is available right after the start (@Startup) of the web application on the application server to ensure that navigational functionality is available no later than actual navigation is required on the application. It is a session component because we provide navigation on a per-user basis. For instance, we keep track of the number of opened dialogs which is obviously on a per-user basis.

We also apply another controller (ControllerPreparation) that we inject from the session context. We will see its preparative usage somewhat later.

Page 257: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Dialogs: Pop-Up Your Web Application!

[ 244 ]

Next, we declare our flexible dialog creation method with a pop-up flag to control if the requested dialog is created as a pop-up, or inside the main browser window:

@Beg�n(jo�n = true) public void openPanelledDialog(javax.faces.event.ActionEvent event, Map<String, Object> map, boolean isPopup) { openD�alog(event, �sPopup? "homePopup" : "home", map, �sPopup); }

It calls itself the more general dialog creation method by providing the template page to be used depending on the pop-up flag. This is because we want to use a simpler page for pop-ups (homePopup) that does not apply any tree display on the left hand side.

Keep a note on how we make use of Seam's conversation feature (@Begin). In case we want to keep and manage objects inside a long-running conversation, they would all be available while these methods are carried out.

Creating Trinidad dialogs in the navigation controlInside openDialog, we create a Trinidad dialog in the usual way by using the createView method of ViewHandler and finally passing the resulting UIViewRoot to Trinidad's basic dialog creation method launchDialog:

@Beg�n(jo�n = true) public void openDialog(javax.faces.event.ActionEvent event, String include, Map<String, Object> map, boolean isPopup) { FacesContext context = FacesContext.getCurrentInstance(); // Create the dialog UIViewRoot ViewHandler viewHandler = context.getApplication().getViewHandler(); UIViewRoot dialog = viewHandler.createView(context, ApplicationConstants.SLASH_SYMBOL + include + ApplicationConstants.XHTML_EXTENSION); setPopup(isPopup); Map<String,Object> windowProperties = null; �f(�sPopup) { windowProperties = new HashMap<String,Object>(); windowProperties.put("width", new Integer(ApplicationConstants.DIALOG_WIDTH)); windowProperties.put("height", new Integer(ApplicationConstants.DIALOG_HEIGHT)); }

Page 258: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 12

[ 245 ]

Noteworthy is the flexible case differentiation that allows making the dialog a pop-up by passing windowProperties which are either null (isPopup=false), or setup according to standard pop-up window size (isPopup=true):

getTrinidadContext().launchDialog(dialog, map, event.getComponent(), �sPopup, w�ndowPropert�es); setDialogOpened(); }

Now we provide the inverse—we add a dialog close method: public void closeDialog() { if(isDialogOpened()) { if(!isPopup()) getTrinidadContext().returnFromDialog(null,null); numberOfOpenedDialogs--; } }

This method is not really interesting. However, it shows how specific requirements lead to a special treatment of such general-purpose functionality. In this specific case, because there is no extra close button on our pop-up dialogs, we can assume that on a pop-up dialog only the X could have been clicked that includes an automatic call of returnFromDialog. Thus, only when it's not a pop-up we have to call Trinidad's returnFromDialog explicitly.

Ensuring correct partial page renderingNext, we find a simple but helpful refinement of Trinidad's partial page rendering that additionally checks whether the respective component is available on the current view root, otherwise raising a NullPointerException:

/** * This is a slightly more robust wrapper for PPR's * addPartialTarget because it ensures that the component to be * refreshed is actually existent otherwise an exception is raised * @param componentId id of the component to be refreshed */ public static void refresh(String componentId) throws NullPointerException { UIComponent u�c = getV�ewRoot().f�ndComponent(componentId); �f(u�c!=null) getTrinidadContext().addPartialTarget(uic); else throw new NullPo�nterExcept�on("<nav�>: part�al target cannot be set on a null component!"); }

Page 259: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Dialogs: Pop-Up Your Web Application!

[ 246 ]

The functionality is more refined than it appears at the first sight. It also ensures that it has a view root that is properly populated with the current contents. We make sure of this by using our own getViewRoot method:

/** * NOTE it may well be that the JSF tree is not available from the * current FacesContext thus it is taken at the time after the * validation step in the JSF life cycle where it is * there for sure * @return the current view root */ public static UIViewRoot getViewRoot() { UIV�ewRoot v�ewRoot = RefreshPhaseL�stener.v�ewRoot; if(viewRoot!=null) return viewRoot; else return getFacesContext().getViewRoot(); }

Depending on the current position within the respective life cycle, it may well be that the view root is not fully instantiated. This is not really astonishing because it is clear that there are some points in the cycle where the JSF view tree cannot be fully built as long as validation has not successfully completed. However, we can keep the latest successfully built tree to set our partial targets, which is enough for Trinidad to have partial page rendering working. In most cases, fetching the view root from the current FacesContext should be enough. If not, the preceding solution provides us with a more robust PPR.

Ensuring availability of the JSF tree, here is the phase listener we need to keep the latest JSF tree:

@SuppressWarnings("serial")publ�c class RefreshPhaseL�stener �mplements PhaseL�stener {

public static UIViewRoot viewRoot;

publ�c vo�d afterPhase(PhaseEvent arg0) { PhaseId phaseId = arg0.getPhaseId(); // NOTE because the JSF tree is available here at this point // of the JSF life cycle we keep it for later refresh �f((phaseId.equals(PhaseId.PROCESS_VALIDATIONS))) v�ewRoot = FacesContext.getCurrentInstance(). getV�ewRoot(); }

public void beforePhase(PhaseEvent arg0) { }

Page 260: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 12

[ 247 ]

public PhaseId getPhaseId() { return PhaseId.ANY_PHASE; }}

In the after phase of validation, we set the JSF tree so we have it available for later usage before further cycles follow. A JSF phase listener needs to be activated in the faces-config.xml:

<lifecycle> <phase-listener> com.test.tr�n�dadSeam�dadAppl�cat�on.RefreshPhaseL�stener </phase-listener></lifecycle>

Standard context retrieval methodsBack to our navigator, we find a series of standard convenience methods there to fetch the Trinidad and Faces context. We also find shorthand for executing JavaScript on the client by using Trinidad functionality:

public static RequestContext getTrinidadContext() { return RequestContext.getCurrentInstance(); }

public static FacesContext getFacesContext() { return FacesContext.getCurrentInstance(); }

public void doJavaScript(String script) { Service.getRenderKitService(getFacesContext(), ExtendedRenderKitService.class).addScript(getFacesContext(), script); }

A few setters and getters follow for tracking the current state of the dialog:

public boolean isDialogOpened() { return this.numberOfOpenedDialogs>0; }

private void setDialogOpened() { this.numberOfOpenedDialogs++; }

public boolean isPopup()

Page 261: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Dialogs: Pop-Up Your Web Application!

[ 248 ]

{ return popup; }

private void setPopup(boolean popup) { this.popup = popup; }

Calling the proper preparation methodNext is the method where the already mentioned ControllerPreparation comes into play:

private Map callPrepareMethod(String methodName) { Map prepareObjectsMap = null; Method[] methods = ControllerPreparation.class.getDeclaredMethods(); for (Method method : methods) { if(method.getName().equals(methodName)) { try { prepareObjectsMap = (Map)method.�nvoke(controllerPrepare, null); break; } catch(InvocationTargetException ite) { log.error("the method to be invoked has an invocation error:"+ite.getMessage()); break; } catch(IllegalAccessException iae) { log.error("the method to be invoked has an access error:"+iae.getMessage()); break; } } } return prepareObjectsMap; }

It is a general approach that allows calling a preparation method by simply passing the respective method name; the method itself is supposed to reside in the preparation controller (ControllerPreparation).

Page 262: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 12

[ 249 ]

We can even shorten this approach by profiting from Seam's Reflections class:

private Map<String, Object> callPrepareMethod(String methodName){ Method method = Reflections.getMethod(ControllerPreparation.class, methodName); return (Map<String, Object>)method.invoke(controllerPrepare, (Object[])null);}

The resulting navigation pointNow, we can look at the heart of our navigator, the navigate method:

public void navigate(boolean isDialog, boolean isPopup, String methodName, ActionEvent event) { //NOTE we setup PPR before opening the panelled dialog // otherwise the refresh does not work unless you use the // more robust PPR refinement refresh which needs a phase // listener to save the JSF tree so it can be used for // refresh later.. Map prepareObjectsMap = callPrepareMethod(methodName); �f(!�sPopup) getTr�n�dadContext().addPart�alTarget( getFacesContext().getViewRoot().findComponent( CommonID.componentAccordion)); if(isDialog) { //if another is open close it before closeDialog(); openPanelledD�alog(event, prepareObjectsMap, �sPopup); } else { // we need to transfer the required data objects on our // own in the already existing page flow scope Map<String,Object> pageFlowMap = getTrinidadContext(). getPageFlowScope(); for (Iterator iterator = prepareObjectsMap.keySet().iterator(); iterator.hasNext();) { String elt = (String)iterator.next(); pageFlowMap.put(elt, prepareObjectsMap.get(elt)); } } }}

Page 263: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Dialogs: Pop-Up Your Web Application!

[ 250 ]

The resulting navigation point has a series of interesting points:

It implements the standard sequence of preparation, creation, and post-processing. For instance, we can see that the preparation method is called before the actual dialog or page is refreshed.There is a subtle refresh issue to be observed—if the dialog is not shown as a pop-up, we need to refresh the page to date up the changed view. This is not only unnecessary, but it would even confuse the pop-up because the page flow would be bound to the main page's dialog and thus the domain objects required in the pop-up will not be available.The navigator supports three possible views:

dialogs on main pages (main browser window)no dialogs, just using the main browser windowpop-up dialogs

When a dialog is to be shown, it closes a possible predecessor.When no dialog is used, the usage of the page flow scope involves the self-built provisioning of the required domain object or objects because only Trinidad dialogs include an automatic transfer of the passed map into its dialog page flow scope.

To see how our navigator is applied, we can inspect the tree controller's usage discussed in the upcoming section. The following screenshot shows the table example as a pop-up dialog reusing the same panel structure:

•°°°

••

Page 264: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 12

[ 251 ]

Making a dialog-enabled tree control We extend our tree controller by the use of three controller components that encapsulate the functionalities of navigation, panel display, and domain data preparation:

@Name("controllerTree")public class ControllerTree extends ChildPropertyTreeModel {

@In Nav�gator nav�; @In ControllerPanel controllerPanel; @In ControllerPreparat�on controllerPrepare;

private void addNode(String include, String nodeLabel, ArrayList<TreeNode> successors, String... prepareMethodName) throws NotSupportedException { TreeNode node = new TreeNode(include,nodeLabel); //show them all in non-popup Trinidad dialogs :) node.setDialog(true); node.setPopup(false); if (prepareMethodName.length>0) node.setPrepareMethodName(prepareMethodName[0]); successors.add(node); }

The preceding addNode method provides us with a means for the creation of a tree item node that is equipped with information on it being shown as a dialog or even as a pop-up. Furthermore, it also sets up the name of the method in the preparation controller that is used to prepare the domain data, provided the client of this method has provided such a method name.

Next, we can see a more general version of this method that is used alongside. It simply allows passing a pop-up flag to setup the node to be displayed in a dialog provided we pass isPopup as true:

private void addNode(String include, String nodeLabel, ArrayL�st<TreeNode> successors, boolean �sPopup, String... prepareMethodName) throws NotSupportedException { TreeNode node = new TreeNode(include,nodeLabel); //show them all in Trinidad dialogs :) node.setDialog(true); node.setPopup(�sPopup); if (prepareMethodName.length>0) node.setPrepareMethodName(prepareMethodName[0]); successors.add(node); }

Page 265: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Dialogs: Pop-Up Your Web Application!

[ 252 ]

Creating concrete tree contentsNow, we are able to create the tree with mixed contents—nodes that are displayed as pop-up dialogs and nodes that are displayed as non-pop-up dialogs:

/** * Default tree nodes * * @return default tree node hierarchy * @throws NotSupportedException */ @Create public void setupTreeNodes() throws NotSupportedException { TreeNode root = new TreeNode(TreeNode.rootInclude,TreeNode.rootIncludeLabel); ArrayList<TreeNode> successors = new ArrayList<TreeNode>(); root.setSuccessors(successors); addNode("ch.I-1/authorization","Chapter 1", successors); addNode("ch.I-2/testFieldSelect","Chapter 2", successors); addNode("ch.II-�/table","Chapter II-�", successors, true, "prepareTableDialogMap"); addNode("ch.II-4/tableGrows","Chapter II-4 Ex.2", successors, "prepareTableGrowsDialogMap"); addNode("ch.II-4/treeTable","Chapter II-4 Ex.3", successors, "prepareTreeTableDialogMap"); addNode("ch.II-4/table-binding","Chapter II-4 Ex.4", successors, "prepareTableBindingDialogMap"); addNode("ch.II-�/chart", "Chapter II-� Bar", successors, true, "prepareChartBarDialogMap"); addNode("ch.II-5/horizontalChart", "Chapter II-5 Horizontal Bar", successors, "prepareChartBarDialogMap"); addNode("ch.II-5/stackedChart", "Chapter II-5 Stacked Bar", successors, "prepareChartStackedBarDialogMap"); addNode("ch.II-5/pie", "Chapter II-5 Pie", successors, "prepareChartPieDialogMap"); addNode("ch.II-5/area", "Chapter II-5 Area", successors, "prepareChartAreaDialogMap"); addNode("ch.II-5/stackedArea", "Chapter II-5 Stacked Area", successors, "prepareChartStackedBarDialogMap"); addNode("ch.II-5/line", "Chapter II-5 Line", successors, "prepareChartLineDialogMap"); addNode("ch.II-5/barLine", "Chapter II-5 Bar Line", successors, "prepareChartBarLineDialogMap"); addNode("ch.II-5/XYLine", "Chapter II-5 XY Line", successors, "prepareChartXYLineDialogMap"); addNode("ch.II-5/scatterPlot", "Chapter II-5 Scatter Plot", successors, "prepareChartScatterPlotDialogMap"); addNode("ch.II-5/radar", "Chapter II-5 Radar", successors, "prepareChartRadarDialogMap");

Page 266: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 12

[ 253 ]

addNode("ch.II-5/radarArea", "Chapter II-5 Radar Area", successors, "prepareChartRadarDialogMap"); addNode("ch.II-5/radarArea2", "Chapter II-5 Radar Area 2", successors, "prepareChartRadarAreaDialogMap"); addNode("ch.II-5/funnel", "Chapter II-5 Funnel", successors, "prepareChartPieDialogMap"); addNode("ch.II-5/circularGauge", "Chapter II-5 Circular Gauge", successors, "prepareChartGaugeDialogMap"); addNode("ch.II-5/semiCircularGauge", "Chapter II-5 Semi- circular Gauge", successors, "prepareChartGaugeDialogMap"); addNode("home", "Chapter II-6 Wizard", successors, "prepareWizard"); addNode("layout/empty","Chapter 3",successors); create(root); }

The highlighted lines show the node creations where we choose to use pop-up dialogs.

Standard tree methodsBefore we move on to the navigational heart of the tree controller, we have a few standard methods (it has partly already been discussed in Chapter 8, Growing a Tree):

public TreeModel getTree() { return this; }

public void back(ReturnEvent event) { navi.closeDialog(); }

/** * used to setup the tree node hierarchy at runtime * @param nodes is the tree node hierarchy to setup the tree model * @throws IntrospectionException occurs */ public void create(TreeNode tree) { this.setWrappedData(tree); this.setChildProperty("successors"); }

Actually, the newly introduced method is the back method that makes sure the respective dialog has been closed after returning from it. In the following application of our tree tag, we see its expected usage.

Page 267: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Dialogs: Pop-Up Your Web Application!

[ 254 ]

Providing navigational attributesMoreover, we can see how the tree node dialog or pop-up flag data including the prepare method name is passed to the tree controller's navigation method by the effective use of JSF's f:attribute tag:

<tr:tree value="#{controllerTree.tree}" var="node" initiallyExpanded="true"><f:facet name="nodeStamp"> <ui:fragment> <tr:commandLink rendered="#{node.rendered}" text="#{node.label}" act�onL�stener="#{controllerTree.nav�gate}" returnL�stener="#{controllerTree.back}" partialSubmit="true" disabled="#{empty node.include or controllerPanel.contentPanel.include eq node.include}"> <f:attribute value="#{node.include}" name="include" /> <f:attribute value="#{node.content}" name="isContent" /> <f:attribute value="#{node.label}" name="label" /> <f:attr�bute value="#{node.d�alog}" name="�sD�alog" /> <f:attr�bute value="#{node.popup}" name="�sPopup" /> <f:attr�bute value="#{node.prepareMethodName}" name="prepareMethodName" /> </tr:commandLink></ui:fragment> </f:facet></tr:tree>

The tree's navigation methodThe navigate method, the client of this tag, now fetches all these attributes simply by using the standard JSF component's getAttributes method:

public void navigate(ActionEvent event) { Map<String,Object> map = event.getComponent().getAttributes(); boolean isContent = ((Boolean)map.get("isContent")). booleanValue(); // if isContent is false, do not use the main content panel // but the description panel area PanelModel panel = isContent? controllerPanel.getContentPanel() : controllerPanel.getDescriptionPanel(); panel.setInclude((String)map.get("include")); panel.setLabel((String)map.get("label")); String methodName = (String)map.get("prepareMethodName"); Boolean �sPopupParam = (Boolean)map.get("�sPopup"); boolean �sPopup = �sPopupParam != null && �sPopupParam. booleanValue();

Page 268: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 12

[ 255 ]

Boolean isDialogParam = (Boolean)map.get("isDialog"); boolean �sD�alog = �sPopup | (�sD�alogParam != null && isDialogParam.booleanValue()); nav�.nav�gate(�sD�alog, �sPopup, methodName, event); }}

The method closes with the call of navigate—the navigator's main method we discussed in the foregoing paragraph.

The following screenshot shows the bar chart, now inside of a pop-up dialog:

Page 269: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Dialogs: Pop-Up Your Web Application!

[ 256 ]

Revisiting the wizard—few additions make it pop-upTo make the wizard compatible with the pop-up variation of Trinidad dialogs, a few enhancements must be added. First, we need to add a node item to provide a link to the pop-up version of the wizard:

addNode("layout/empty", "Chapter II-6 Wizard Popup", successors, true, "prepareWizard");

Thus, when the tree is created another additional item appears. As for the original wizards, it calls the same prepare method. However, it references an empty include file because the pop-up needs an initial empty page content state for the include technique to work properly with Facelets (otherwise we run into an endless loop). Moreover, we pass the pop-up flag as true to get the pop-up version of a Trinidad dialog by means of the standard navigator whose dialog creation method, however, needs slight enhancement to provide a parameterized pop-up window size:

@Begin(join = true) public void openDialog(javax.faces.event.ActionEvent event, String include, Map<String, Object> map, boolean isPopup) { FacesContext context = FacesContext.getCurrentInstance(); // Create the dialog UIViewRoot ViewHandler viewHandler = context.getApplication().getViewHandler(); UIViewRoot dialog = viewHandler.createView(context, ApplicationConstants.SLASH_SYMBOL+ include+ApplicationConstants.XHTML_EXTENSION); setPopup(isPopup); Map<String,Object> windowProperties = null; if(isPopup) { windowProperties = new HashMap<String,Object>(); �f(map.conta�nsKey("w�dth")) { w�ndowPropert�es.put("w�dth",map.get("w�dth")); w�ndowPropert�es.put("he�ght", map.get("he�ght")); } else { windowProperties.put("width", new Integer(ApplicationConstants.DIALOG_WIDTH)); windowProperties.put("height", new Integer(ApplicationConstants.DIALOG_HEIGHT)); } } ...

Page 270: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Chapter 12

[ 257 ]

Therefore, if we pass the additional parameters width and height to the map, they are taken instead of the standard size from ApplicationConstants.

The following screenshot shows the wizard inside of a pop-up dialog:

Now, we can pass a more adequate size for the wizard pop-up:

/** * @return a map containing all the data for the page flow to be used to access the wizard */ public Map<String,Object> prepareWizard() { Wizard wizardModel = new Wizard(); Map<String,Object> map = new HashMap<String, Object>(); map.put("wizard", wizardModel); map.put("w�dth", new Integer(��0)); map.put("he�ght", new Integer(�00)); return map; }

Page 271: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Dialogs: Pop-Up Your Web Application!

[ 258 ]

The rest stays the same! No further change is required because once the wizard pop-up dialog is up, the single wizard steps are inside this dialog and do not need to be treated as single dialogs (nor as single pop-up dialogs, of course). Thus, the navigation defaults to the Trinidad refresh combination with include files—in other words, we have originally seen the panel-based PPR technique earlier in Chapter 8, Growing a Tree, and refined it in the Defining a dialog-enabled navigation control section of this chapter.

SummaryWe have seen how the Trinidad dialog framework can be used as central means of navigation while the conventional page navigation as defined in the pages.xml can be reduced to a minimum.

To make this possible, we have first taken a look at how to keep a Seam conversation during Trinidad dialogs. This is achieved by using Trinidad's pageFlowScopeProvider to pass the Seam conversation to the Trinidad dialog.

We saw how to define a dialog-enabled navigation control that creates Trinidad dialogs on its own and ensures correct partial page rendering. Further refinements were applied to ensure the availability of the JSF tree and to provide standard context retrieval methods. The navigation control culminates in its resulting navigation method. Where, first, the respective state preparation method is called by reflection and second, the parameterized type of navigation that may either be a dialog, a pop-up dialog, or just the main browser window with any dialog at all.

We have learned how to make a dialog-enabled tree control that creates concrete tree contents, and applies standard tree methods. We also learned how navigational attributes are provided on the XHTML side. In the tree's navigation method we could then see how these attributes are fetched and then passed to the navigation control's navigation.

Finally, we revisited the wizard and added just a few additions to enhance it with a pop-up mode.

Page 272: Apache Myfaces Trinidad 1.2 A Practical Guide (November

ReferencesThe appendix includes a list of links to important and relevant sites as well as documentation found in the Internet, many of them linking to the Trinidad web site.

Links to the Apache MyFaces Trinidad web siteAlthough links to the Apache MyFaces Trinidad seems rather obvious to be included as a list of links, a couple of links are not as obvious as one might think. In particular, the site does not yet make it easy to reach a couple of substantial links, thus it will most probably be highly valuable to the reader to find here a list of important, working links available for gaining information on Trinidad:

Trinidad - Index (Main Site): http://myfaces.apache.org/trinidadTrinidad - Configuration: http://myfaces.apache.org/trinidad/devguide/configuration.html

Developer's Guide Index: http://myfaces.apache.org/trinidad/devguide/index.html

Trinidad Component Demos: http://www.irian.at/trinidad-demo/faces/componentDemos.jspx

Tag library documentation: http://myfaces.apache.org/trinidad/trinidad-api/tagdoc.html

Trinidad Java API: http://myfaces.apache.org/trinidad/trinidad-api/apidocs/index.html

Trinidad Skinning: http://myfaces.apache.org/trinidad/devguide/skinning.html

Trinidad Skinning FAQ: http://wiki.apache.org/myfaces/Trinidad_Skinning_FAQ

Page 273: Apache Myfaces Trinidad 1.2 A Practical Guide (November

References

[ 260 ]

Trinidad SVN Repository: http://svn.apache.org/repos/asf/myfaces/trinidad

Converting JSF Tags to Trinidad Tags: http://myfaces.apache.org/trinidad/spec-diff.html

Trinidad Partial Page Rendering: http://myfaces.apache.org/trinidad/devguide/ppr.html

Cl. Converters/Validators: http://myfaces.apache.org/trinidad/devguide/clientValidation.html

Trinidad JIRA: https://issues.apache.org/jira/browse/TRINIDADTrinidad And Seam - MyFaces Wiki: http://wiki.apache.org/myfaces/Trinidad_And_Seam

References

Chapter 1Trinidad JIRA: https://issues.apache.org/jira/browse/TRINIDADTrinidad Skinning: http://myfaces.apache.org/trinidad/devguide/skinning.html

Trinidad JSF12 Support: http://wiki.apache.org/myfaces/Trinidad_JSF12_Support

Seam Framework (Main Site): http://www.seamframework.orgSeam Documentation: http://labs.jboss.com/jbossseam/docsSeam pure Java Authorization: http://www.mail-archive.com/[email protected]/msg109452.html

Trinidad - Configuration: http://myfaces.apache.org/trinidad/devguide/configuration.html

Chapter 2JavaServer Facelets: https://facelets.dev.java.net/Facelets fit JSF: http://www.ibm.com/developerworks/java/library/j-facelets1.html

Advanced Facelets: http://www.ibm.com/developerworks/java/library/j-facelets2.html

Page 274: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Appendix

[ 261 ]

Improving JSF by Dumping JSP Article by Hans Bergsten on www.onjava.com

http://drewdev.blogspot.com/2008/03/build-time-vs-render-time.html

http://www.ilikespam.com/blog/c%3Aforeach-vs-ui%3Arepeat-in-facelets

http://drewdev.blogspot.com/2008/08/cforeach-with-jsf-could-ruin-your-day.html

Chapter 3Tag Library Documentation: http://myfaces.apache.org/trinidad/trinidad-api/tagdoc.html

Trinidad Java API: http://myfaces.apache.org/trinidad/trinidad-api/apidocs/index.html

Chapter 4Trinidad Partial Page Rendering: http://myfaces.apache.org/trinidad/devguide/ppr.html

Firefox Plugins: https://pfs.mozilla.org/plugins/

Chapter 5Dialog Framework: http://myfaces.apache.org/trinidad/devguide/dialogs.html

Seam Documentation: http://labs.jboss.com/jbossseam/docsSeam pure Java Authorization: http://www.mail-archive.com/[email protected]/msg109452.html

Chapter 6Tag Library Documentation: http://myfaces.apache.org/trinidad/trinidad-api/tagdoc.html

Trinidad Skinning: http://myfaces.apache.org/trinidad/devguide/skinning.html

Page 275: Apache Myfaces Trinidad 1.2 A Practical Guide (November

References

[ 262 ]

Chapter 7JavaServer Facelets: https://facelets.dev.java.net/Facelets fit JSF: http://www.ibm.com/developerworks/java/library/j-facelets1.html

Advanced Facelets: http://www.ibm.com/developerworks/java/library/j-facelets2.html

Tab Indices Design Plans: https://issues.apache.org/jira/browse/TRINIDAD-888

Panel Form Layout: http://myfaces.apache.org/trinidad/trinidad-api/tagdoc/tr_panelFormLayout.html

Chapter 8Tree Tag: http://myfaces.apache.org/trinidad/trinidad-api/tagdoc/tr_tree.html

Trinidad Partial Page Rendering: http://myfaces.apache.org/trinidad/devguide/ppr.html

Chapter 9Trinidad Tables: http://myfaces.apache.org/trinidad/devguide/table.html

Table Tag: http://myfaces.apache.org/trinidad/trinidad-api/tagdoc/tr_table.html

treeTable Tag: http://myfaces.apache.org/trinidad/trinidad-api/tagdoc/tr_treeTable.html

Chapter 10Chart Component: http://myfaces.apache.org/trinidad/devguide/chart.html

Chart Tag: http://myfaces.apache.org/trinidad/trinidad-api/tagdoc/tr_chart.html

Page 276: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Appendix

[ 263 ]

Chapter 11SingleStepButtonBar tag: http://myfaces.apache.org/trinidad/trinidad-api/tagdoc/tr_singleStepButtonBar.html

Facelet JIRA issue: https://issues.apache.org/jira/browse/ TRINIDAD-26

Chapter 12Dialog Framework: http://myfaces.apache.org/trinidad/devguide/dialogs.html

PageFlowScopeProvider: http://wiki.apache.org/myfaces/Trinidad_And_Seam

Trinidad Partial Page Rendering: http://myfaces.apache.org/trinidad/devguide/ppr.html

Page 277: Apache Myfaces Trinidad 1.2 A Practical Guide (November
Page 278: Apache Myfaces Trinidad 1.2 A Practical Guide (November

IndexSymbols<accessibility-mode> parameter 26<accessibility profile> parameter 26<client-validation> parameter 26<debug-output> parameter 26<page-flow-scope-lifetime> parameter 26<trh:body> 53<trh:cellFormat> 54<trh:head> 53<trh:html> 53<trh:rowLayout> 54<trh:script> 53<trh:tableLayout> 54@In(scope=ScopeType.<CONVER

SATION|SESSION|PAGE|..>, required=<true|false>, value="<SeamName>") 16

@In annotation 16@Name(<'SeamName'>) annotation 16@Out(scope=ScopeType.<CONVE

RSATION|SESSION|PAGE|..>, required=<true|false>, value="<SeamName>") 16

@Out annotation 16

Aabstract class design, aspects

backStepAction 228backStepListener 228decrementStep 227getSelectedStep 227getSelectedStepIndex 227incrementStep 227initializeModel method 228

nextStepAction 228nextStepListener 228setSelectedStepIndex 227

abstract wizard modelabstract class design, aspects 227, 228action method 225actionListener method 225constructors 224, 225current step index, controlling 226current step method 225decrementation methods 227defining 223incrementation methods 227maxSteps properties 223number of wizard steps, controlling 226properties 223, 224

accessKey attribute 58accordion and showDetailItem, combining

about 120, 121content panel 123ControllerPanel 124Facelets, alternative 122, 123toolbar facet 125-127

actionListener attribute 59actions attribute 61addPartialTarget 83addPartialTarget(UIComponent newTarget)

83addPartialTargets (UIComponent compo-

nent, String... relativeTarget) 83addPartialTriggerListeners(UIComponent

listener, String[] trigger) 83Advanced Facelets 260, 262allDetailsEnabled attribute 63application context 17

Page 279: Apache Myfaces Trinidad 1.2 A Practical Guide (November

[ 266 ]

application, setting upabout 97, 98Seam-gen used 99-100

area chartsabout 209, 210stackedArea type 209

attributeChangeListener attribute 57attributes, in command and navigation

componentsblocking attribute 60launchListener 60partialSubmit attribute 60textAndAccessKey attribute 60useWindow attribute 60windowHeight attribute 60windowWidth attribute 60

attributes, in large input and output components

tag attributes, for table, treeTable, and tree 61

tag attributes, for table and treeTable 61, 62tag attributes, for tree 63tag attributes, for tree and treeTable 62tag attributes, for treeTable 63

attributes, in tag and display tagsabout 58accessKey 58actionListener 59autoSubmit 59contentStyle 58converter 59disabled 58immediate 59label 58labelAndAccessKey 58onblur 59onchange 59onfocus 59readOnly 58required 59requiredMessageDetail 59returnListener 59showRequired 59simple 59validator 59

value 59valueChangeListener 59

authorizationabout 93hasRightAccess 93Seam 18-24user authorization 94XHTML, equipping 93

autoSubmit attribute 59

BbackStepAction 228backStepListener 228bar charts

about 202-205getGroupLabels method 203getMinYValue method 206getSeriesLabels method 203horizontalBar type 202maxPrecision 203stackedHorizontalBar type 202stackedVerticalBar type 202stacking 205-207verticalBar type 202

barLine type 211binding, attributeChangeListener

inlineStyle 58onclick 57ondblclick 57onkeydown 57onkeypress 57onkeyup 57onmousedown 57onmousemove 57onmouseout 57onmouseover 57onmouseup 57partialTriggers 58shortDesc 57styleClass 58

binding attribute 57blocking attribute 60browser client setup 109, 110business process context 17

Page 280: Apache Myfaces Trinidad 1.2 A Practical Guide (November

[ 267 ]

CCACHE_VIEW_ROOT parameter 27CHANGE_PERSISTENCE parameter 28CHECK_FILE_MODIFICATION parameter

25chart component

about 201, 202, 262area charts 209, 210bar charts 202-205funnel chart 219gauge chart 219-221line charts 211line charts type 211pie charts 207radar chart 215scatterPlot chart 214

Chart tag 262ChildPropertyTreeModel, 2

extending, to Seam component 158, 159setChildProperty 155setWrappedData 155

CircularGauge type 219Cl. Converters/Validators 260CLIENT_STATE_MAX_TOKENS

parameter 27CLIENT_STATE_METHOD parameter 27closeDialog method 92columnBandingInterval attribute 62commandButton component 183commandLink component 240commandLink

using, to create clickable tree node 162component library structure 51composition components

fieldDate component 137-138fieldNumber component 139-141fieldSelect component 142, 143fieldText component 135-137

concrete wizardaction listeners, implementing 228, 229application, inside preparation controller

231defining 228implementation, design aspects 234navigation, implementing 229step object, implementing 230

wizard instance, initializing 230, 231content panel 123contentStyle attribute 58controller-enhanced tree models 175ControllerPanel 124controllerPanel.descriptionPanel.include

123controllerPanel.descriptionPanel.label 123controllerPanel.descriptionPanel.opened

123controllerPanel.descriptionPanel.rendered

123conversation context 17convertor attribute 59core.data 55core.input

API, hierarchy 56core.input API 56core.layout 55core.model 55core.nav 54core.output 55CoreTable object 191createComponent factory method 192currency-code parameter 27

DDEBUG_JAVASCRIPT parameter 25decimal-separator parameter 27decrementation methods 227decrementStep 227deployment, Seam-gen

about 101from Eclipse 106-108Trinidad-specific and Facelet-related

changes 103, 104Trinidad-specific and Facelet-related

changes, to project files 102-104Trinidad-specific changes, to Ant build

script 105Developer Guide Index 259dialog-enabled navigation control, defining

advantages 243navigate method 249partial page rendering, ensuring 245-247

Page 281: Apache Myfaces Trinidad 1.2 A Practical Guide (November

[ 268 ]

proper preparation method, calling 248, 249

standard context, retrieval methods 247, 248

Trinidad dialogs, creating in navigation control 244, 245

dialog-enabled tree control, creatingabout 251addNode method 251concrete tree contents, creating 252, 253getAttributes method 254navigate method 254, 255navigational attributes, providing 254

standard tree methodsDialog Framework

about 90, 261-263closeDialog method 92data flow, providing from dialog to dialog

91dialog, creating programmatically 91dialog, returning from 92returnFromDialog method 92

dialogParameters 92DISABLE_CONTENT_COMPRESSION

parameter 25disabled attribute 58discloseMany attribute 116discloseNone attribute 116disclosedRowKeys attribute 61

EEclipse

deployment from 106-108Eclipse project

application, setting up with 99, 100Eclipse project, setting up

Seam-gen used 99, 100ENABLE_LIGHTWEIGHT_DIALOGS

parameter 25event context 17

FFacelet composition components

about 36applying 44creating 37, 38

declaring 38id parameter 38labelStyle attribute 40labelStyle parameter 38margin parameter 38model attribute 38model parameter 38msgLabel attribute 39msgLabel parameter 38parameters 38readOnly parameter 38required parameter 38requisites 36visible attribute 39visible parameter 38width parameter 38

Facelet JIRA issue 263Facelet parameters

about 122panelDescriptionAreaInsert 122panelDescriptionAreaOpen 122panelDescriptionAreaRendered 122panelDescriptionAreaTitle 122

Facelet page compositionabout 30-34templates used 34, 35Trinidad tags used 30Ui-prefixed Facelet tags 34

Faceletsabout 29advantages 29, 30in real life projects 48tips 47, 48

Facelets fit JSF 260-262FacesServlet 30fieldDate component 46, 137-138fieldNumber component 139-141fieldSelect component 142, 143fieldText component 135-137Firefox Plugins 261focusRowKey attribute 62footer attribute 61form, building

composition components, building 135form submission controls used 148general message area, adding 152panelFormLayout instances used 145

Page 282: Apache Myfaces Trinidad 1.2 A Practical Guide (November

[ 269 ]

part of form processing, Trinidad subforms used 149-151

formatting-locale parameter 27funnel chart 219

Ggauge chart

about 219CircularGauge type 219getMaxYValue method 221getMinYValue method 221getYValues method 221semiCircularGauge type 219

general row methods 174getMaxYValue method 221getMinYValue method 221getPartialTargets(UIComponent compo-

nent) 83getSelectedRowData 183getSelectedRowKeys 183getSelectedStep 227getSelectedStepIndex 227getSupportedLocales() method 39getYValues method 221

Hheader attribute 61horizontalBar type 202horizontalGridVisible attribute 62hyper links 87

II18n

about 95on internal Facelet composition components

95on single labels 95

id attribute 57id parameter 38immediate attribute 59include attribute 117incrementStep 227initiallyExpanded attribute 62

initializeModel method 228inlineStyle attribute 58internationalization. See I18ninterval attribute 96isEmpty method 188

JJava-side PPR, RequestContext used

about 84partial target, adding 84PPR source, defining 84

JavaServer Facelets 260, 262JavaServer Faces. See JSF componentJSF component 7JSF Tags

converting, to Trinidad tags 260JSTL

structure 45, 46tips 47, 48using 45

JSTL structure<c:if test='<EL-condition>'> ... </c:if> 45<c:set var="<ParameterName" value="Para

meterValue"/> 45

Kkeyboard shortcuts 117

LlabelAndAccessKey attribute 58label attribute 58, 117labelStyle attribute 40labelStyle parameter 38launchDialog method 91launchListener attribute 60line charts

about 211-214line type 211XYLine type 211

line type 211links 87localeSelector object 39lookupInStatefulContexts method 17

Page 283: Apache Myfaces Trinidad 1.2 A Practical Guide (November

[ 270 ]

Mmargin attribute 41margin parameter 38model-view tree, extending

about 163AbstractTreeNode class, properties 164AbstractTreeNode constructors 164controller-enhanced tree models 175getters, abstracted 166getters, for accessing new state 170helper methods, modified 165helper methods, new 165internal navigation, testing 176new tree model, preparing for 164new tree model, Trinidad's abstract

TreeModel based 168, 169new tree node, implementations for new

tree model 167, 168new TreeNode, implementations 167, 168row disclosure testing, RowDisclosureEvent

listener used 169tree traversal, Trinidad's container methods

used 171setters, abstracted 166

model attribute 38model parameter 38msgLabel attribute 39msgLabel parameter 38

Nnavigate method 254, 255navigation

approaches 88, 90navigation, Seam

levels 17navigationTree viewer 154new tree model, model-view tree

AbstractTreeNode, constructors 164, 165AbstractTreeNode, properties 164getters, abstracted 166helper methods, modified 165helper methods, new 165new tree node, implementation 167, 168new TreeNode, implementation 166, 167setters, abstracted 166

new tree model, Trinidad's abstract TreeModel

about 168getters, for accessing new state 170row disclosure testing, RowDisclosureEvent

listener used 169tree traversal 170tree traversal, Trinidad's container methods

used 171, 172nextStepAction 228nextStepListener 228nodeStamp attribute 62nodeStamp facet

using, to generate tree 161number-grouping-separator parameter 27

Oonblur attribute 59onchange attribute 59ondblclick attribute 57onfocus attribute 59onkeydown attribute 57onkeypress attribute 57onkeyup attribute 57onmousedown attribute 57onmousemove attribute 57onmouseout attribute 57onmouseover attribute 57onmouseup attribute 57opened attribute 117oracle-help-servlet-url parameter 26outputText partialTrigger 183

PpanelAccordion

about 115discloseMany attribute 116discloseNone attribute 116

panel components 114page context 17pageFlowScope 92PageFlowScopeProvider 241, 263panelDescriptionAreaInsert 122panelDescriptionAreaOpen 122panelDescriptionAreaRendered 122

Page 284: Apache Myfaces Trinidad 1.2 A Practical Guide (November

[ 271 ]

panelDescriptionAreaTitle 122Panel Form Layout 262panelFormLayout, attributes

fieldWidth 143labelWidth 143maxColumns 143rows 143

panelFormLayout instancesused, for form building 145

panelModel componentabout 116include attribute 117label attribute 117opened attribute 117rendered attribute 117

panels, skinningabout 128accordion, skinning 128accordion's children specific properties,

skinning 130skins, switching on configuration level

130-132Partial Page Rendering. See PPRpartialSubmit attribute 60partialTriggers attribute 58pie charts 207Plain Old Java Object. See POJOPOJO 117PollEvent listener

example 96polling

attributes 96interval, attribute 96PollEvent listener 96pollListener, attribute 96requirements, fulfilling 96

pollListener attribute 96PPR

about 65and rendered attribute 79Java-side PPR, Trinidads RequestContext

used 82, 83tag-based PPR 65, 66with server-side caching, pageFlowScope

used 70, 71with tr:selectOneChoice 71, 72

with tr:selectOneChoice component and actionListener 76-78

with tr:selectOneChoice component and valueChangeListener 73-75

proper preparation method 248public Map<Object, Object>

getReturnParameters() method, ReturnEvent object 92

public Object getReturnValue() method, ReturnEvent object 92

RradarArea type 215radar charts

about 215image 216radar type 215radarArea type 215series 217

rangeChangeListener 61readOnly attribute 58readOnly parameter 38reference implementation. See RIreflexive PPR 80rendered attribute 57RequestContext object

using 82launchDialog method 91returnFromDialog method 92

required attribute 59requiredMessageDetail attribute 59required parameter 38ReturnEvent object

public Map<Object, Object> getReturnParameters() method 92

public Object getReturnValue() method 92returnFromDialog method 92RI 11right-to-left parameter 27rootNoteRendered attribute 63rowBandingInterval attribute 62rowDisclosureListener 61row index methods 173, 174row key methods 173rows attribute 62rowsByDepth attribute 63rowSelection attribute 62

Page 285: Apache Myfaces Trinidad 1.2 A Practical Guide (November

[ 272 ]

SScatterPlot chart type 214Seam-gen

application, setting up with 97-99deployment 101

Seamabout 13, 14authorization 18-24conversations 16, 17navigation 17with Trinidad 14, 15

Seam, with Trinidad@In(scope=ScopeType.<CONVE

RSATION|SESSION|PAGE|..>, required=<true|false>, value="<SeamName>") 16

@In annotation 16@Name(<'SeamName'>) annotation 16@Out(scope=ScopeType.<CONVE

RSATION|SESSION|PAGE|..>, required=<true|false>, value="<SeamName>") 16

@Out annotation 16application context 17business process context 17context management 17conversation content 17event content 17lookupInStatefulContexts method 17page content 17session content 17

Seam documentation 260, 261Seam Framework (Main Site) 260Seam pure Java authorization 260, 261selectedRowKeys attribute 61selectionListener 61semiCircularGauge type 219session context 17setChildProperty, ChildPropertyTreeModel

155setSelectedStepIndex 227setWrappedData, ChildPropertyTreeModel

155shortDesc attribute 57showDetailItem components

about 115, 116

toolbar, 6toolbar facet 125

showRequired attribute 59simple attribute 59simplified mode 18SingleStepButtonBar tag 263skins

switching 130switching, ways 131

skinningacordion 128, 129acordion's children, specific properties 130panels 128

sortListener 61sortProperty 184spider diagram. See radar chartsstackedArea type 209stackedHorizontalBar type 202stackedVerticalBar type 202standard tag attributes

about 57attributeChangeListener 57binding, attributeChangeListener 57id 57rendered 57

standard tag attributes, in tag groupsabout 58attributes, in command 60attributes, in display tags 58attributes, in form 58attributes, in large input and output

components 60attributes, in navigation components 60

styleClass attribute 58summary attribute 62

TTab indices design plans 262table-related methods 174, 175table component

aboutbanding, adding 191button bar, adding 185, 186detail data sub views, adding 186, 187Facelets, using for encapsulation 191-194getSelectedRowData 180

Page 286: Apache Myfaces Trinidad 1.2 A Practical Guide (November

[ 273 ]

grids, adding 191JSF binding, using for encapsulation

191-194outputText partialTriggers 183pageFlowScope 180paging, adding 188-190POJO data model used 186, 187search form, adding 188-190selection listener, adding 182, 183sorting, adding 184sortProperty 184tableModel 180tableSelect method 183uses 179, 180XHTML, creating 194

tableSelect method 183Table tag 262tag-based PPR

about 66autoSubmit attribute 66id attribute 66partialSubmit attribute 66partialTriggers attribute 66PPR and rendered attribute 79, 80trigger, finding 67with server-side caching, pageFlowScope

used 70with tr:selectOneChoice 71, 72with tr:selectOneChoice component and

actionListener 76-78with tr:selectOneChoice component and

valueChangeListener 73-75tag attributes, for table, treeTable, and tree

disclosedRowKeys 61selectedRowKeys 61var, varStatus 61

tag attributes, for table and treeTableactions 61columnBandingInterval 62footer 61header 61horizontalGridVisible 62rangeChangeListener 61rowBandingInterval 62rows 62rowSelection 62sortListener 61

summary 62verticalGridVisible 62width 62

tag attributes, for treeallDetailsEnabled 63

tag attributes, for tree and treeTablefocusListener 62focusRowKey 62initiallyExpanded 62nodeStamp 62

tag attributes, for treeTablerootNoteRendered 63rowsByDepth 63

Tag library documentation 259-261textAndAccessKey attribute 60time-zone parameter 26toolbar facet

about 125, 126fullViewDescription.xhtml 126templateDescriptionFullView.xhtml 126

tr:inputText component 67tr:, Trinidad's core tag library namespace 56treeTable component

about 195table capabilties, adding 196-199uses 195, 196

treeTable tag 262tree components

about 153BaseMenuModel 154ChildPropertyTreeModel 154MenuModel 154models 154navigationTree, viewers 154tree, viewers 154TreeModel 154treeTable, viewers 154viewers 154

tree model, buildingabout 157, 158addPartialTarget method 160ChildPropertyTreeModel, extending to

Seam component 158, 159controllerPanel 158-160navigation component, applying for basic

navigation control 160, 161panels for navigation, preparing 159, 160

Page 287: Apache Myfaces Trinidad 1.2 A Practical Guide (November

[ 274 ]

tree tag 262TreeNode Model

creating 155-157successors attribute 155

tree traversal, Trinidad's container methods used

about 171, 172general row methods 174row index methods 173, 174row key methods 172, 173table-related methods 174

tree viewer 170trh, Trinidad XHTML tag library namespace

<trh:body> 53<trh:cellFormat> 54<trh:head> 53<trh:rowLayout> 54<trh:script> 53<trh:tableLayout> 54about 53

trh tag library, 4trigger, tag-based PPR

finding 67MVC (Model-View-Controller) setup,

ensuring 69partialTriggers attribute, ensuring 68PPR trigger ID, ensuring 68PPR, with rendered attribute 70refreshed fields, ensuring 69Trinidad configuration, ensuring 68

trinidad.convert 55trinidad.event 55trinidad.validator 55Trinidad

advantages 9, 10background 7, 8component library structure 51, 52core tag library namespace 56Dialog Framework 90features 9, 10namespaces 52selecting, key criteria 10-12tree components 151

Trinidad dialogsabout 242creating, in navigation control 244, 245using, in web application 239

Trinidad selecting, key criteriaactivity example 11adequacy 12browser and platform support 12component range 11design quality 12documentation 12Facelet support 11framework character 11functional range 11interoperability 11maturity 10panel components 113skinnability 12support 11

Trinidad, configuration parametersin trinidad-config.xml 26in web.xml 27, 28

trinidad-config.xml, special parameterscurrency-code 27decimal-separator 27formatting-locale 27number-grouping-separator 27oracle-help-servlet-url 26right-to-left 27time-zone 26two-digit-year-start 27uploaded-file-processor 27

trinidad-config.xml, Trinidad configuration parameters

<accessibility-mode> 26<accessibility profile> 26<client-validation> 26<debug-output> 26<page-flow-scope-lifetime> 26special parameters 26

Trinidad - Configuration 259, 260Trinidad - Index (Main Site) 259Trinidad And Seam - MyFaces Wiki 260Trinidad Component Demos 259Trinidad dialogs

about 242creating, in navigation control 244, 245using, in web application 239

Trinidad Java API 261Trinidad JIRA 260Trinidad JSF12 Support 260

Page 288: Apache Myfaces Trinidad 1.2 A Practical Guide (November

[ 275 ]

Trinidad, namespacestr: 52trh: 52

Trinidad Partial Page Rendering 260-263Trinidad Skinning 260, 261

about 259FAQ 259

Trinidad SVN Repository 260Trinidad tables 262two-digit-year-start parameter 27

Uui-prefixed Facelet tags, Facelet page com-

position<ui:include src="FileToInclude" /> 34<ui:insert /> 34<ui:insert name="NameOfArea">

DefaultContent </ui:insert> 34uploaded-file-processor parameter 27USE_APPLICATION_VIEW_CACHE

parameter 28user authorization 94useWindow attribute 60

Vvalidator attribute 59value attribute 59valueChangeListener 73valueChangeListener attribute 59ValueExpression 193var, varStatus attribute 61verticalBar type 202verticalGridVisible attribute 62visible attribute 39visible parameter 38

Wweb.xml, special parameters

CACHE_VIEW_ROOT 27CHANGE_PERSISTENCE 28CLIENT_STATE_MAX_TOKENS 27CLIENT_STATE_METHOD 27USE_APPLICATION_VIEW_CACHE 28

web.xml, Trinidad configuration parametersCHECK_FILE_MODIFICATION 25

DEBUG_JAVASCRIPT 25DISABLE_CONTENT_COMPRESSION 25ENABLE_LIGHTWEIGHT_DIALOGS 25

width attribute 62width parameter 38windowHeight attribute 60windowProperties 245windowWidth attribute 60wizard

revisiting 257, 258wizard Facelet tag

applying, to XHTML side 234wizard implementation, design aspects

about 232initializeModel attribute 233

XXHTML

commandLink, using to create clickable tree node 162

creating 161node parameters, passing to navigation

control 162, 163nodeStamp facet, using to generate tree 161

XHTML sidedefining 234wizard Facelet tag, applying 234

XHTML tag library namespace (trh) 53XYLine type 211

Yy-axis curve 211y-axis values 203

Page 289: Apache Myfaces Trinidad 1.2 A Practical Guide (November
Page 290: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Thank you for buying Apache MyFaces Trinidad 1.2

Packt Open Source Project RoyaltiesWhen we sell a book written on an Open Source project, we pay a royalty directly to that project. Therefore by purchasing Apache MyFaces Trinidad 1.2, Packt will have given some of the money received to the Apache MyFaces project.In the long term, we see ourselves and you—customers and readers of our books—as part of the Open Source ecosystem, providing sustainable revenue for the projects we publish on. Our aim at Packt is to establish publishing royalties as an essential part of the service and support a business model that sustains Open Source.If you're working with an Open Source project that you would like us to publish on, and subsequently pay royalties to, please get in touch with us.

Writing for PacktWe welcome all inquiries from people who are interested in authoring. Book proposals should be sent to [email protected]. If your book idea is still at an early stage and you would like to discuss it first before writing a formal book proposal, contact us; one of our commissioning editors will get in touch with you. We're not just looking for published authors; if you have strong technical skills but no writing experience, our experienced editors can help you develop a writing career, or simply get some additional reward for your expertise.

About Packt PublishingPackt, pronounced 'packed', published its first book "Mastering phpMyAdmin for Effective MySQL Management" in April 2004 and subsequently continued to specialize in publishing highly focused books on specific technologies and solutions. Our books and publications share the experiences of your fellow IT professionals in adapting and customizing today's systems, applications, and frameworks. Our solution-based books give you the knowledge and power to customize the software and technologies you're using to get the job done. Packt books are more specific and less general than the IT books you have seen in the past. Our unique business model allows us to bring you more focused information, giving you more of what you need to know, and less of what you don't.Packt is a modern, yet unique publishing company, which focuses on producing quality, cutting-edge books for communities of developers, administrators, and newbies alike. For more information, please visit our website: www.PacktPub.com.

Page 291: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Apache Geronimo 2.1: Quick ReferenceISBN: 978-1-847196-94-1 Paperback: 310 pages

Develop applications on Geronimo using Java EE 5 quickly and easily

1. Gain a deep understanding of the rich set of features provided by Apache Geronimo 2.1.4

2. Develop and deploy your Java EE 5 applications on Geronimo with easy-to-use tooling support

3. Create database pools and establish connectivity with all the supported databases using Geronimo

4. Master the server administration and customize the server with your own plugins

5. Step-by-step instructions with plenty of examples and sample applications

Apache Struts 2 Web Application DevelopmentISBN: 978-1-847193-39-1 Paperback: 384 pages

A beginner’s guide for Java developers

1. Design, develop, test, and deploy your web applications using Struts 2 framework

2. No prior knowledge of JavaScript and CSS is required

3. Apply the best of agile development techniques and TDD techniques

4. # Step-by-step instructions and careful explanations with lots of code examples

Please check www.PacktPub.com for information on our titles

Page 292: Apache Myfaces Trinidad 1.2 A Practical Guide (November

Tomcat 6 Developer's GuideISBN: 978-1-847197-28-3 Paperback: 416 pages

Build better web applications by learning how a servlet container actually works

1. Build a Tomcat distribution from its source code, and explore the components, classes, and technologies that make up this container

2. Use standard development tools such as Eclipse, Ant, and Subversion to dissect a Tomcat distribution

3. Discover the touch points between the servlet specification and a servlet container's implementation

4. Acquire specialist grade skills in a range of technologies that contribute to Java server side development

Apache Maven 2 Effective ImplementationISBN: 978-1-847194-54-1 Paperback: 456 pages

Build and Manage Applications with Maven, Continuum, and Archiva

1. Follow a sample application which will help you to get started quickly with Apache Maven

2. Learn how to use Apache Archiva - an extensible repository manager - with Maven to take care of your build artifact repository

3. Leverage the power of Continuum - Apache's continuous integration and build server - to improve the quality and maintain the consistency of your build

4. Guidance on how to use Maven in a team environment to maximise its potential

Please check www.PacktPub.com for information on our titles