Monday, April 29, 2013

How-to cloudbees minuteproject 4 primefaces

Introduction

Cloudbees offers JEE app and Mysql DB storage.
Minuteproject generates CRUD and reporting application for Primefaces based on a database model.

This article is based on upon the petshop mysql database.
The result can be show on cloudbees at http://petshopapp.minuteproject.cloudbees.net

The application, minuteproject configuration and DB model can be found on google code at https://code.google.com/p/minuteproject/downloads/detail?name=petshop-mp4primeface-cloudbees.zip

Prerequisits

Download and install Minuteproject set MP_HOME
Download and install Cloudbees SDK set BEES_HOME
Create a cloudbees account
Mysql local DB running with a schema.

Steps

In order to get Cloudbees Primefaces application quickly follow the next steps.

Cloudbees setups

Cloudbees setup can be done on the website, but also by the following command lines

Cloudbees app

$bees app:create petshopapp

Cloudbees  DB

$bees db:create petshopappDB -u username -p password

Cloudbees binding

$bees app:bind -db petshopappDB -a petshopapp -as petshopAppDS

Deployment on Cloudbees

$bees app:deploy -a account/petshopapp -t tomcat7 path-to-your-app.war
This step is performed after you have build your app.

Install you DB schema

Get the server connection information:
  • server
  • port
  • user_name
  • pass_word

$mysql --user=user_name --password=pass_word --host=server --port=port < schema.sql

Minuteproject 4 Primefaces app

To create a primefaces application, minuteproject can generate one based on a database structure.
Minuteproject runs with a command line.
The configuration file used is petshop-mp4primeface-cloudbees.zip 

Configuration

The configuration file can be found in the zip under mp-config-JSF-Spring.xml
The main points of the file are
<!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="mysql" version="5.1.16" groupId="mysql"
                    artifactId="mysql-connector-java"></driver>
                <dataSource>
                    <driverClassName>org.gjt.mm.mysql.Driver</driverClassName>
                    <url>jdbc:mysql://127.0.0.1:3306/petshop</url>
                    <username>root</username>
                    <password>mysql</password>
                </dataSource>
                <primaryKeyPolicy oneGlobal="false">
                    <primaryKeyPolicyPattern name="autoincrementPattern"></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" >
        <field name="DESCRIPTION" ordering="asc" label="my description" is-searchable="true"></field>
        <field name="NAME" ordering="asc" ></field>
        <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 city, count(*) as nb from address group by city order by count(*) desc limit ? ]]>
                            </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 lcase(city) like ?]]>
                            </value>
                         </query-body>
                         <query-params>
                             <query-param name="city" type="STRING" sample="'S'" convert="lowercase,append%" default="%">
                             </query-param>
                         </query-params>
                     </query>
                </queries>
            </statement-model>
  </model> 
The database driver is mysql and the primary key strategy is autoincrement for not natural primary key
Product and Item tables have been aliased
Product and Item tables goes in product package, which means graphically a distinct menu access.
Category is a reference-data table, which means caching and access via drop down list

Statement:
Misc statement queries can be used to produce report in forms of list, pie-chart, bar-chart.

Generate

Copy the file in $MP_HOME/mywork/config From a prompt run
$model-generation mp-config-JSF-Spring.xml

Build

The generation result is in $MP_HOME/dev/JSF/petshop From a prompt run
$mvn clean package

Customise package for cloudbees


Cloudbees context

Optional step to perform if your not creating the binding between the Application and DB.

Add a Cloudbees file context.xml

In /WEB-INF/lib add context.xml in war/META-INF
<Context>
<Resource name="jdbc/petshopAppDS"
            auth="Container"
            type="javax.sql.DataSource"

            url="jdbc:${DATABASE_URL}"
            username="${USER_NAME}"
            password="${PASS_WORD}"

            driverClassName="com.mysql.jdbc.Driver"

            maxActive="20"
            maxIdle="1"
            maxWait="10000"
            removeAbandoned="true"
            removeAbandonedTimeout="60"
            logAbandoned="true"

            validationQuery="SELECT 1"
            testOnBorrow="true"
            />
</Context>

The ${DATABASE_URL} is retrieved from 

$bees db:info petshopapp

Persistence.xml

adapt persistence.xml with Cloudbees binding alias
change non-jta-data-source node with java:comp/env/jdbc/petshopAppDS
remove properties hibernate connection info

The persistence.xml is located in petshopBackEnd-1.0-SNAPSHOT.jar!/META-INF

<?xml version="1.0"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
             version="1.0">
<!--MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @PERSISTENCE-UNIT-petshop@-->
    <persistence-unit name="petshop">
<!--MP-MANAGED-UPDATABLE-ENDING-->
<non-jta-data-source>java:comp/env/jdbc/petshopAppDS</non-jta-data-source>
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <!-- pet --> 
        <class>net.sf.mp.demo.petshop.domain.pet.Address</class>
        <class>net.sf.mp.demo.petshop.domain.pet.Category</class>
        <class>net.sf.mp.demo.petshop.domain.pet.Sellercontactinfo</class>
        <class>net.sf.mp.demo.petshop.domain.pet.Tag</class>
        <class>net.sf.mp.demo.petshop.domain.pet.Ziplocation</class>

        <!-- product --> 
        <class>net.sf.mp.demo.petshop.domain.product.MyGoodItem</class>
        <class>net.sf.mp.demo.petshop.domain.product.MyGoodProduct</class>


        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
            <property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.SingletonEhCacheProvider" />
            <property name="net.sf.ehcache.configurationResourceName" value="/ehcache.xml" />
            <property name="hibernate.cache.use_query_cache" value="true" />
            <property name="hibernate.cache.use_second_level_cache" value="true" />
<!--MP-MANAGED-ADDED-AREA-BEGINNING @properties@-->
<!--MP-MANAGED-ADDED-AREA-ENDING @properties@-->
        </properties> 


<!--MP-MANAGED-ADDED-AREA-BEGINNING @persistence-unit@-->
<!--MP-MANAGED-ADDED-AREA-ENDING @persistence-unit@-->
    </persistence-unit>

<!--MP-MANAGED-ADDED-AREA-BEGINNING @persistence@-->
<!--MP-MANAGED-ADDED-AREA-ENDING @persistence@-->

</persistence>


Deploy

$bees app:deploy -a account/petshopapp -t tomcat7 JSF/target/petshopApp.war
where account is the account you created

Tomcat7 target ensure the EL libraries are present.

Result


Improvements

For those who think it's a bit long, they are right!
Most of the step could be simplified since most of it could be generated!

Minuteproject will add a cloud track with cloudbees for that in the next release.


1 comment: