Creating SeamDiscs X

This example was built using seam-gen. To add in Trinidad, the trinidad-api jar was added to the ear (and referenced from `application.xml`) and the trinidad-impl jar, `jboss-seam-trinidad.jar` (Seam-Trinidad integration) & `a4j-trinidad.jar` (RichFaces Ajax-Trinidad integration) were added to `WEB-INF/lib`.

A few alterations were needed in `web.xml` and `faces-config.xml`.

The `trinidad-config.xml` file was used to disable client-side validation for a more consistent user experience.

Of course Trinidad and RichFaces offer some complementary components (e.g. tables, trees) - it's up to you which you choose!

`web.xml` X

    <context-param>
       <param-name>
          org.apache.myfaces.trinidad.ALTERNATE_VIEW_HANDLER
       </param-name>
       <param-value>
          com.sun.facelets.FaceletViewHandler
       </param-value>
    </context-param>

    <filter>
       <filter-name>Trinidad</filter-name>
       <filter-class>
          org.apache.myfaces.trinidad.webapp.TrinidadFilter
       </filter-class>
    </filter>

    <filter-mapping>
       <filter-name>Trinidad</filter-name>
       <url-pattern>*.seam</url-pattern>
    </filter-mapping>

    <servlet>
       <servlet-name>Trinidad Resources</servlet-name>
       <servlet-class>
          org.apache.myfaces.trinidad.webapp.ResourceServlet
       </servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>Trinidad Resources</servlet-name>
        <url-pattern>/adf/*</url-pattern>
    </servlet-mapping>

`faces-config.xml` X

    <application>
       <!-- Disabled when using RichFaces or Trinidad -->
       <!--
       <view-handler>
          com.sun.facelets.FaceletViewHandler
       </view-handler>
       -->
       <!-- Enable Trinidad renderkit -->
       <default-render-kit-id>
          org.apache.myfaces.trinidad.core
       </default-render-kit-id>
    </application>

`application.xml` X

    <module>
       <java>trinidad-api-1.0.0-incubating.jar</java>
    </module>

RichFaces Ajax and Trinidad X

Trinidad and RichFaces Ajax both provide partial page refresh and submit. For Trinidad PPR to work, it needs to be surrounded by a component which enables PPR. The example uses `<tr:panelPartialRoot />` to achieve this:

    <tr:panelPartialRoot>
       <tr:form>
          <tr:table value="#{artists.dataModel}" var="artist">
             <tr:column>
                ...

If you want to use RichFaces' partial page refresh with Trinidad components then you'll need to disable Trinidad's compressed style keys:

    <context-param>
       <param-name>
          org.apache.myfaces.trinidadinternal.DISABLE_CONTENT_COMPRESSION
       </param-name>
       <param-value>true</param-value>
    </context-param>

Inplace editing X

The example also shows how you can use Trinidad components to achieve "in-place" editing - the same views are used to display and edit informtation. A casual visitor to the site navigates around, and see's the components in read only mode; once logged in, these components are editable, and button's are rendered to submit information.

    <tr:inputText
       label="Artist"
       value="#{artist.name}"
       readOnly="#{not identity.loggedIn}"
       required="true"
       autoSubmit="true"/>

Trinidad makes it easy by providing a `readOnly` attribute for components - but you could easily achieve the same using Seam's `<s:decorate />` tag.

Seam Application Framework X

The example uses the Seam Application Framework. Where possible XML is used, using extension only where extra functionality is needed.

An `EntityHome` and is used for each CRUD, and an `EntityQuery` for clickable lists.

If you extend `EntityHome` you can make the component an EJB3 stateful session bean by adding `@Stateful` and a local interface. You'll need to declare methods like `persist()` and `isManaged()` from `EntityHome` on the interface. The `ArtistHome` is a stateful session bean in this example.

Each item in the list can be clicked - an `<s:link />` and an `<f:param />` is used to link to the detail view. It's wired using `pages.xml`.

The CRUD page uses the `EntityHome` object to create, update or delete the entity as necessary. `pages.xml` is used to direct the user back to the list view.

`Clickable lists` X

    <s:link action="artist">
        <tr:outputText value="#{artist.name}" />
        <f:param name="artistId" value="#{artist.id}" />
    </s:link>

    <page>
       <param name="artistId" value="#{artistHome.id}"
          converterId="javax.faces.Integer"/>
       <navigation>
          <rule if-outcome="artist">
             <begin-conversation flush-mode="manual"/>
             <redirect view-id="/artist.xhtml"/>
          </rule>
       </navigation>
    </page>

`components.xml` X

    <framework:entity-home
       entity-class="org.jboss.seam.example.seamdiscs.model.Disc"
       name="discHome"/>
    <factory
       name="disc"
       value="#{discHome.instance}"/>

    <framework:entity-query
       name="discs"
       ejbql="select disc from Disc disc"
       order="disc.name ASC"
       max-results="5"/>

`CRUD` X

    <h:commandButton action="#{artistHome.update}"
       value="Save" rendered="#{artistHome.managed}" />
    <h:commandButton action="#{artistHome.persist}"
       value="Save" rendered="#{not artistHome.managed}" />
    <s:button action="cancel" value="Cancel" />

    <page>
       <param name="artistId" value="#{artistHome.id}"
          converterId="javax.faces.Integer"/>
       <navigation>
          <rule if-outcome="cancel">
             <end-conversation/>
             <redirect view-id="/artists.xhtml" />
          </rule>
          <rule if-outcome="updated">
             <end-conversation/>
             <redirect view-id="/artists.xhtml" />
          </rule>
          <rule if-outcome="persisted">
             <end-conversation/>
             <redirect view-id="/artists.xhtml" />
          </rule>
       </navigation>
    </page>

Using Trinidad's Tree X

It's been said that the quality of a tree component is an indication of the quality of a component set. Trinidad has a really robust tree component, - but it's `TreeModel` can be a bit confusing. Luckily it provides a good default implementation - the `ChildPropertyTreeModel`.

The `ChildPropertyTreeModel` takes two parameters - the `Collection` to use for the tree's nodes, and a `String` property which specifies the field or get/set pair to use for accessing each elements child. If the property returns `null`, then the node is a leaf-node.

The example uses a slightly modified `ChildPropertyTreeModel` - one that says discs are the leaves of the tree. Different labels are rendered depending on the type of node.

`Tree` X

    public TreeModel getTree() {
       return new ChildPropertyTreeModel(artists, "discs") {
          protected Object getChildData(Object parentData) {
             if (parentData instanceof Artist) {
                return super.getChildData(parentData);
             } else {
                return null;
             }
          }
       };
    }

    <tr:tree value="#{artistHome.tree}" var="var">
       <f:facet name="nodeStamp">
          <ui:fragment>
             <s:link
                   action="artist"
                   rendered="#{var.class.simpleName eq 'Artist'
                      or var.class.simpleName eq 'Band'}">
                <tr:outputText value="#{var.name}" />
                <f:param name="artistId" value="#{var.id}" />
             </s:link>
          </ui:fragment>
       </f:facet>
    </tr:tree>

Look and Feel X

Both Trinidad and RichFaces have powerful and mature skinning/theming APIs - so you all you need to do is write some CSS! For seamdiscs, we took a RichFaces skin, and adjusted the trinidad skin to fit with it. To do this, we added the skin to `trinidad-skins.xml`, and told Trinidad to use it in `trinidad-config.xml`. You can find more information about Trinidad skinning on the Trinidad wiki.

You'll notice that Trinidad and RichFaces components don't provide a consistent look-and-feel out of the box - there are plans afoot to improve this!

Enhanced `DataModel` X

JSF component sets like Trinidad, Tomahawk and IceFaces give you an enhanced `h:dataTable` which has built-in sorting, paging and other goodies. However, there is one big flaw - the entire data set is loaded and sorted/paged in memory, when really you want to get your persistence layer (be it an ORM or just a database) to do this for - a sort translates naturally to an `ORDER BY`, and paging translates naturally to a `LIMIT` clauses.

Seam on the other hand provides tight integration to your persistence layer, and supports paging and sorting of queries through the `Query` object in the Seam Application Framework - but you have to write a load more JSF to get it integrated. We can get the best of both worlds by using the enhanced `DataModel` in Trinidad, which supports paging and sorting backed by a `Query`.

The `jboss-seam-trinidad.jar` (built using the build file in the `trinidad` directory in Seam CVS) provides a `DataModel` which, when backed by a `Query`, provides lazy loading of data for paging, sorting in the persistence context and strong row keys. You can use it by adding the `jboss-seam-trinidad.jar` to your `WEB-INF/lib` - no need to alter your facelet. One caveat is that you must ensure the rows property on the `Query` is the same as the `maxResults` property on the `Query`. Take a look at the seamdiscs example in the `trinidad/examples` directory to see it in action.

    <tr:table
          value="#{discs.dataModel}"
          rows="#{discs.maxResults}">
       <tr:column>
          ...
       </tr:column
    </tr:table>

Powered by Seam Creating SeamDiscs RichFaces Ajax and Trinidad Inplace Editing Seam Application Framework Look and Feel Enhanced DataModel Tree Component Generated by seam-gen.