Primefaces technology is available at http://primefaces.org/. Shortname in this page 'PF'.

MinuteProject 4 Primefaces-spring generates a primefaces presentation stack managing CRUD and SDD operations on top of Spring/ JPA2 (BSLA) backend.

This page will show you the steps to
  • generate
  • package
  • deploy a working JSF-primefaces application.


Architecture

Three-tier architecture:
  • Persistence with JPA2
  • DAO with BSLA (Basic Spring Layer Architecture) that offers CRUD, pagination...
    • Contains also global model service facilities
  • Presentation layer with Managed-beans, Controller and jsf2 pages

Generated Artifacts

In this page are only mentioned the artifacts related to Primefaces track. Click for information related to JPA2 and BSLA.

The artifacts are gathered inside a maven project whose structure is the following

PF-spring-mvn_structure.png


The JSF Primefaces artifacts generated per entity
  • Controller
  • Converter
  • LazyPortlet.xhtml
  • LazyList.xhtml
  • Create/Edit (xhtml)
  • ListRow (xhtml)
  • Semantic Reference (xhtml) as a composite definition

Global
  • Menu (java/xhtml)
  • some Utils (JsfManagedBeanUtils, JsfUtils)
  • i18n bundle
  • Decorator.xhtml for the tile of the site
  • web.xml
  • application-context (xml) for spring integration
  • PortletDecorator
  • various Portlet/Liferay xml files


Generation

Via the console
  1. Start the MP console (<MP_HOME>/bin/start-console.(cmd/sh). How to use the console.
  2. Fill the connection information to the datamodel
  3. Fill the model general information (model, package names, version primary key policy, scope).
  4. Choose JSF-Primefaces target
  5. Click generate

Via the configuration file
An example can be found <MP_HOME>/demo/config/mp-config-JSF-spring.xml.
To run it: execute demo-JSF-primefaces.(cmd/sh)

Target Configuration used in mp-config-JSF-spring.xml adapted to use a hsqldb database as a server instance and not as a file storage.

<!DOCTYPE root>
<generator-config xmlns="http://minuteproject.sf.net/xsd/mp-config"
xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
xs:noNamespaceSchemaLocation="mp-config.xsd">
    <configuration>
        <conventions>
            <target-convention type="enable-updatable-code-feature" />
        </conventions>
        <model name="petshop" version="1.0" package-root="net.sf.mp.demo">
            <data-model>
                <driver name="hsqldb" version="1.8.0.7" groupId="hsqldb" artifactId="hsqldb"></driver>
                <dataSource>
                    <driverClassName>org.hsqldb.jdbcDriver</driverClassName>
                     <url>jdbc:hsqldb:hsql://127.0.0.1:9001/petshop</url>
                    <username>sa</username>
                    <password></password>
                </dataSource>
 
                <primaryKeyPolicy oneGlobal="true" oneForEachTable="false">
                    <primaryKeyPolicyPattern prefix="" suffix="" name="sequencePattern" sequenceName="hibernate_sequence"></primaryKeyPolicyPattern>
                </primaryKeyPolicy>
            </data-model>
            <business-model>
                <generation-condition>
                    <condition type="exclude" startsWith="DUAL"></condition>
                    <condition type="exclude" startsWith="ID_GEN"></condition>
                    <condition type="exclude" startsWith="SEQUENCE"></condition>
                </generation-condition>
                <business-package default="pet">
                    <condition type="package" startsWith="PRODUCT" result="product"></condition>
                    <condition type="package" startsWith="ITEM" result="product"></condition>
                </business-package>
                <enrichment>
                   <conventions>
                      <entity-naming-convention type="apply-strip-table-name-prefix" pattern-to-strip="SYS,FIN"/>
                      <reference-naming-convention type="apply-referenced-alias-when-no-ambiguity" is-to-plurialize="true"></reference-naming-convention>
                   </conventions>
                    <package name="product">
                        <entity-group entities="PRODUCT"></entity-group>
                        <entity-group entities="ITEM"></entity-group>
                    </package>
                    <entity name="PRODUCT" alias="MY_GOOD_PRODUCT">
                    </entity>
                    <entity name="ITEM" alias="MY_GOOD_ITEM" comment="my item table">
                        <field name="PRODUCTID" alias="THIS_IS_MY_PRODUCT" comment="my product field reference"></field>
                    </entity>
                    <entity name="CATEGORY" content-type="reference-data" >
                       <semantic-reference>
                         <sql-path path="NAME"/>
                       </semantic-reference>
                    </entity>
                </enrichment>
            </business-model>
            <statement-model>
                <queries>
                     <query name="get address abstract" id="dashAddress" type="dashboard" category="pie-chart">
                         <query-body> <!-- dimensions column first -->
                         <value>
<![CDATA[select top ? city, count(*) as nb from address group by city order by count(*) desc]]>
                            </value>
                         </query-body>
                         <query-params>
                             <query-param name="top city" is-mandatory="false" type="INT" sample="37" default="10"></query-param>
                         </query-params>
                     </query>
                     <query name="get address summary" id="dashCity" type="dashboard" category="bar-chart">
                         <query-body> <!-- dimensions column first -->
                         <value>
<![CDATA[select city, count(*) as nb, count(*) as nb2 from address group by city order by count(*) desc]]>
                            </value>
                         </query-body>
                     </query>
                     <query name="get addresses by criteria" id="c">
                         <query-body><value>
<![CDATA[select * from address where latitude between ? and ? and longitude between ? and ? and lcase(city) like ?]]>
                            </value></query-body>
                         <query-params>
                             <query-param name="latitude_lower_limit" is-mandatory="false" type="DOUBLE" sample="37"></query-param>
                             <query-param name="latitude_upper_limit" type="DOUBLE" sample="38"></query-param>
                             <query-param name="longitude_lower_limit" type="DOUBLE" sample="-122"></query-param>
                             <query-param name="longitude_upper_limit" type="DOUBLE" sample="-123"></query-param>
                             <query-param name="city" type="STRING" sample="'S'" convert="lowercase,append%" default="%"/>
                         </query-params>
                     </query>
                </queries>
            </statement-model>
    </model>
    <targets catalog-entry="Primefaces-Spring">
    </targets>
   </configuration>
</generator-config>
This file contains the target technology to generate against (Primefaces-Spring) as well as model description and enrichment.

Besides there are some SDD (Statement Driven Development) samples.


Build deploy


Build

In the generated directory there is a global maven pom file, run: mvn package
The build result is in ./JSF-Primefaces/target/petshopApp.war

Deploy

On tomcat

Copy to war to <tomcat>/webapps/
Once tomcat is started it automatically deploys the application that can be tested at localhost:8080/petshopApp


Design questions

Pagination

Pagination use Primefaces lazy model in combination with BSLA pagination facilities based on the mask pattern.

Partial refresh

Partial refresh allows the developer to display a portion on its JSF component on demand.
It is done:
  1. By wrapping the element to display in a simple tag ex: <p:outputPanel id="containerId" > <your JSF element> </p:outputPanel>
  2. Adding to the next JSF node within a wrapper the attribute element "rendered"<p:outputPanel id="containerId" > <p:dialog rendered="${managedBean.isToRender()}">xxx</p:dialog> </p:outputPanel>
  3. Trigger to the change of managedBean.isToRender to true and update the wrapper element <p:commandButton immediate="true" actionListener="#{managedBean.activateRender}" update="containerId" .../>

Partial refresh is used for all SubUC case buttons on a page. SubUC buttons are sub-flow when making a lookup of a parent relationship.

Drop down

//TODO for masterdata and for enum



Result


Search and Edit


AddressList.png

Add element to a collection


AddItemToAddress.png

Affect a parent element to a child element

It is a affectation Sub Use-Case in modal mode.
There is not the possibility to change the relationship with the parent element, only other parent relationships can be looked-up.

ContactInfoSubUCAffectationDone.png

Affectation


ContactInfoSubUCAffectationDone2.png

Many 2 One

There are 2 ways to perform Many to One
  • Via a affectation Sub UseCase
  • Via a drop down list
The drop down list if find if the end entities is a reference or master data (i.e. limited number of entries)
For the rest use affectation Sub UC with pagination.

Many 2 Many

There are 2 ways to perform Many to many just as there are 2 ways to perform one to many
  • Via a affectation Sub UseCase
  • Via a picklist

Example
ITEM table is linked to TAG table via a many to many.
ITEM records are live business data whereas TAG records are masterdata.
In Minuteproject configuration the user can specify which table is considered as master/reference data whether nominatively or globally (by conventions: ex table ending with _TYPE, _STATE...)

Many 2 Many with picklist

In release 0.8.6
PF-spring_m2m_with_master-data.png


Many 2 Many with selection

PF-spring_many-to-many_with_live_business_data.png