Showing posts with label code generator. Show all posts
Showing posts with label code generator. Show all posts

Thursday, September 5, 2013

piping generators with minuteproject

There are couple of really interesting generators working based on some input file and execution principles.
It is easy to understand and tooling-oriented. Input 2 Tool gives Result Code.

Minuteproject principle is the same

When working with generators dealing with RDBMS persistence (Rev-Eng or Fwd-Eng), minuteproject can generate initial input for those generators.

This strategy is called generator piping.

Each generator has its own particularities and kind of DSL.
The goal is then to degrade as less as possible the 'other-generator' input in order to keep the added value as high as possible.


Minuteproject is particularily interested by the following OS generators:
  • Liferay Service Builder
  • JOOQ
  • Benerator
  • Roo (input script instructions)
  • RoR (input script instructions)
  • Propel

Tooling to deal with other generators available in minuteproject
  • Plugin
    • write a mp plugin (java bean match target technology specifics)
    • this plugin is available at template level to query target-generator-centric info.
  • Parametrization
    • offer track customization
    • a classical parameter could be the version of the target generator
  • Updatable code feature
    • tune your output without losing your altertions over consecutive generations
  • Enrichment
    • Conventions
      • Some configuration can be tedious because quite verbose, fortunately minuteproject can pin common caracteristics via conventions
    • Aliasing
      • provides indirection level to have DB names look like DB names and Java name matching Java conventions
The main difficulty is to know what is the input for field type (is it an SQL, UML, Java, own DSL type) that has to be treated at plugin level.

Friday, August 17, 2012

sql query to primefaces app with sdd

Intro

Primefaces provides cool rendering facilities on one hand.
Minuteproject provides reverse-engineering facilities base on relational database but also on sql statement, on the other hand.

Now you have a query and you want to have a primefaces app!... without writing any (ANY) line of code.
This article is for YOU.

If you download Minuteproject 0.8.2+ you can have an example on how-to do it (delivered as a demo).
This article tracks the steps to follow as well as explaining the demo.

Enrichment

You can consult the entire configuration in /demo/config/mp-config-JSF-Spring.xml

statement-driven-development

Minuteproject provides a enrichment area where you can set up your sql queries.
Here is the snippet part correspondinng to the query enrichment inside the statement-model node.

        ....
   <statement-model>
                <queries>
                     <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> 

You specify the name of the query which will be used to create
  • DTO class
  • JSF menu entry
  • JSF URL
  • JSF form name
You specify in question marks the input parameters you want and in query-param what is the name to give them. Those name with be used to create
  • DTO variable
  • JSF form entries with validation

Empower primefaces with minuteproject sdd templates

Primefaces needs to have new templates about what to generate coming from SDD.
This is given in the track 
            <target refname="SDD-beans" 
                outputdir-root="../output/JSF-Spring/JPA2"
               fileName="mp-template-config-SDD-beans.xml" 
               templatedir-root="../../template/framework/bean">
            </target> 

 

Steps

Set-up

  • Download last version of Minuteproject.
  • Unzip in directory
  • Start sample petshop DB: /sample/start-petshop-database.cmd/sh
  • Go to /config/demo
    • Run demo-JSF-Spring-primefaces.cmd/sh
  • Go to /target/mp-bsla
    • Run install-maven.cmd (it installs a MVN dependency for spring DAO that is not yet (sic) in mvn-central)
  • Go to /demo/output/JSF-Spring
    • Run 'mvn clean package'
Alternative run all demos

 

Generated code

You have a JSF primeface 3.3 app with cupertino theme offering Create, List, Delete on entities and with I/O screen of each query here (GetAddressesByCriteriaInput).

The generated code is decomposed into 3 maven project:
  • You have JPA2 backend+ DTOs for each SDD query I/O
  • You have Spring 3 integration with CRUD DAO on top of entity and DAO for SDD query DTOs.  
  • You have a JSF front-end integrated with spring
This way you can easily work with minuteproject Updatable Code feature to get what you customize your artifact without losing the power of consecutive generations.

Deployment

Setup

The resulting application is petshopApp.war in /demo/output/JSF-Spring/JSF/target
It is ready to be dropped on tomcat or other JEE container.
 
But before take care that your EL (expression language jar spec and impl) are 2.2.
On tomcat (check that /lib contains 
  • el-api-2.2.jar
  • el-impl-2.2.jar
Check the stackoverflow entries
Note: that there is no connection pool dependency on the container. By default in nothing is specified in the JPA2 target 'environment' property. The environment is considered has local so no reference to a JNDI CP.

Deploy

Start tomcat (/bin/startup.cmd/sh)
Drop petshopApp.war in /webapps

 

Result

Here is a little UC where we create an address and we retrieve it base on the ad-hoc sdd query.

Create address

List addresses

SDD in action: Use specific criteria to address

Check validation

 

Future

This is not enough...
Why not having multiple statement that works together to produce for example a master-detail or dashboard-master-detail?... primefaces provides nice toolset for that.

Break current limitations
  • SDD in the current form is sql oriented, but nothing prevent from having it REST URL resource oriented.
  • Add validations, mapping, convertions on I/O params.
  • Provide presentation defaulting
  • Provide navigation between SDD components
  • Add filtering and improved query builder

Saturday, February 25, 2012

Productivity by example: Liferay with JOOQ

This article shows how to use jOOQ for the Liferay data model.
Minuteproject generates jOOQ artifacts for Liferay.
The main interest of using minuteproject to generate jOOQ artefacts are 
  • Liferay database does not have any foreign key, but minuteproject is able to detect relationship based on patterns.
  •  Some DB naming convention might need to be adapted at Java level
    • DB tables ending with '_' will have underscore stripped
    • Column name ending with '_id' corresponding to PK or FK will have this particule stripped when not coliding with other variable
  • Code is updatable, meaning that you can change part of it or entirely and consecutive generation will keep your alterations
For more information about the enrichment made on top of Liferay by minuteproject check another post targeting Liferay with JPA2.
Here the reverse-engineering targets jOOQ framework and the configuration mentions jOOQ track reference

Configuration
mp-config-LIFERAY-JOOQ.xml
<!DOCTYPE root>
<generator-config>
 <configuration>
  <conventions>
   <target-convention type="enable-updatable-code-feature" />
  </conventions>
  <model name="liferay" 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/lportal</url>
     <username>root</username>
     <password>mysql</password>
    </dataSource>
    <schema>lportal</schema>
    <primaryKeyPolicy oneGlobal="true">
     <primaryKeyPolicyPattern name="none"></primaryKeyPolicyPattern>
    </primaryKeyPolicy>
   </data-model>
   <business-model>
    <generation-condition>
     <condition type="exclude" startsWith="QUARTZ"></condition>
    </generation-condition>
    <enrichment>
     <conventions>
      <entity-naming-convention type="apply-strip-table-name-suffix"
       pattern-to-strip="_" />
      <!-- manipulate the structure and entities BEFORE manipulating the 
       entities -->
      <foreign-key-convention
       type="autodetect-foreign-key-based-on-similarity-and-map"
       column-ending="id" column-starting="" />
      <column-naming-convention type="apply-strip-column-name-suffix"
       pattern-to-strip="ID" />
      <reference-naming-convention
       type="apply-referenced-alias-when-no-ambiguity" is-to-plurialize="true" />
     </conventions>
    </enrichment>
   </business-model>
  </model>
  <targets>
   <target refname="JOOQ" name="JOOQ" fileName="mp-template-config-JOOQ.xml"
    outputdir-root="../../dev/JOOQ/liferay" templatedir-root="../../template/framework/jooq">
    <property name="jooq-version" value="2.0.4"></property>
   </target>
   <target refname="LIB" fileName="mp-template-config-bsla-LIB-features.xml"
    templatedir-root="../../template/framework/bsla">
   </target>
  </targets>
 </configuration>
</generator-config>
Execution
Install Liferay mysql 6.0.6 running
Download minuteproject
Drop this config in /mywork/config
And execute model-generation.(sh/cmd) mp-config-LIFERAY-JOOQ.xml

Result 
Artifacts
The resulting artefacts are
  • A maven project with following dependencies
    • jOOQ
    • jUnit
    •  mysql drive
  • jOOQ artifacts
    • factory, keys, tables, records...
  • unit test
The artifacts are generated in /dev/JOOQ/liferay
If you build there will be a compilation error in jOOQ artifacts:
Table 'expandotable' has a field call 'table' that collides with a Jooq method. 
But just by altering the code to remove the compilation error and flaging to take into account this modification:
In ExpandotableRecord 
  • Change getTable into getTable_ 
  • Exclude code from been overwritten: line 24 //MP-MANAGED-UPDATABLE-BEGINNING-ENABLE
 //MP-MANAGED-UPDATABLE-BEGINNING-ENABLE @jooq-record-pk-liferay@
 /**
  * An uncommented item
  * 
  * PRIMARY KEY
  */
    public void setTable(java.lang.Long value) {
        setValue(net.sf.mp.demo.liferay.tables.Expandotable.__EXPANDOTABLE.TABLE, value);
    }
 /**
  * An uncommented item
  * 
  * PRIMARY KEY
  */
    public java.lang.Long getTable_() {
        return getValue(net.sf.mp.demo.liferay.tables.Expandotable.__EXPANDOTABLE.TABLE);
    }
 //MP-MANAGED-UPDATABLE-ENDING

Remark: Future version will handle this issue but it is interesting to see how the code can be customized without losing the productivity of consecutive generations.

Eventually run: mvn clean package
  • A set of unittest are executed:
    • The default unit test consist to retrieve the first row of each entity.
  • A JOOQ package is released
Code
The code can be downloaded from minuteproject googlecode here.

Sample
Active record:
Providing the Foreign key gives the ability to provide jOOQ records with some methods
One to many
//todo
Testing

/**
 * This class is generated by minuteproject 4 jOOQ
 */
package net.sf.mp.demo.liferay.tables;

import net.sf.mp.demo.liferay.tables.records.UserRecord;
import net.sf.mp.demo.liferay.Liferay;
import net.sf.mp.demo.liferay.Keys;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

import net.sf.mp.demo.liferay.LiferayFactory;
import static net.sf.mp.demo.liferay.tables.User.__USER;

import org.jooq.Record;
import org.jooq.Result;
import org.junit.Test;

//MP-MANAGED-ADDED-AREA-BEGINNING @import@
import static net.sf.mp.demo.liferay.tables.Company.__COMPANY;
import static net.sf.mp.demo.liferay.tables.Account.__ACCOUNT;
//MP-MANAGED-ADDED-AREA-ENDING @import@

//MP-MANAGED-ADDED-AREA-BEGINNING @class-annotation@
//MP-MANAGED-ADDED-AREA-ENDING @class-annotation@
@javax.annotation.Generated(value = { "http://www.jooq.org", "2.0.4" }, comments = "This class is generated by minuteproject 4 jOOQ")
public class TestUser {

 @Test
 public void testUser() {
  Connection conn = null;
  String userName = "root";
  String password = "mysql";
  String url = "jdbc:mysql://127.0.0.1:3306/lportal";

  try {
   Class.forName("org.gjt.mm.mysql.Driver").newInstance();
   conn = DriverManager.getConnection(url, userName, password);
   LiferayFactory create = new LiferayFactory(conn);

   // MP-MANAGED-UPDATABLE-BEGINNING-ENABLE
   // @jooq-unittest-testUser-liferay@
   // write your own tests, just set DISABLE to ENABLE in the comment
   // above
   // future generation will not erase your code ;)
   Result<Record> result = create
     .select(__USER.FIRSTNAME, __USER.LASTNAME, __COMPANY.WEB, __ACCOUNT.NAME)
     .from(__USER).join(__COMPANY)
     .on(__USER.COMPANY.equal(__COMPANY.COMPANY))
     .join(__ACCOUNT)
     .on(__COMPANY.ACCOUNT.equal(__ACCOUNT.ACCOUNT))
     .where(__COMPANY.WEB.like("%ray.com"))
     .orderBy(__USER.LASTNAME.asc().nullsFirst()).limit(10)
     .fetch();
   for (Record r : result) {
    String firstname = r.getValue(__USER.FIRSTNAME);
    String lastname = r.getValue(__USER.LASTNAME);
    String web = r.getValue(__COMPANY.WEB);
    String accountname = r.getValue(__ACCOUNT.NAME);

    System.out.println(" firstname : " + firstname + " lastname : "
      + lastname + " web : " + web + " accountname : "
      + accountname);
   }
   // MP-MANAGED-UPDATABLE-ENDING

  } catch (Exception e) {
   e.printStackTrace();
  } finally {
   if (conn != null) {
    try {
     conn.close();
    } catch (SQLException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
   }
  }
 }

 // MP-MANAGED-ADDED-AREA-BEGINNING @implementation@
 // MP-MANAGED-ADDED-AREA-ENDING @implementation@

}
Giving at execution
 firstname :  lastname :  web : liferay.com accountname : Liferay
 firstname : Joe lastname : Bloggs web : liferay.com accountname : Liferay
 firstname : Test lastname : DLC 1 web : liferay.com accountname : Liferay
 firstname : Test lastname : DLC 10 web : liferay.com accountname : Liferay
 firstname : Test lastname : DLC 2 web : liferay.com accountname : Liferay
 firstname : Test lastname : DLC 3 web : liferay.com accountname : Liferay
 firstname : Test lastname : DLC 4 web : liferay.com accountname : Liferay
 firstname : Test lastname : DLC 5 web : liferay.com accountname : Liferay
 firstname : Test lastname : DLC 6 web : liferay.com accountname : Liferay
 firstname : Test lastname : DLC 7 web : liferay.com accountname : Liferay
JOOQ quick review
//todo
  • Typesafe query speeds up the development process
  • No ORM 
  • Focus on CRUD and complexe query 
  • No configuration loading meaning fast to test



Tuesday, November 22, 2011

MinuteProject Telosys impedance matching

This article is to review couple of technical points of both generators, and see the different possibilities of integration.
My perception of Telosys is for the moment limited to what I learned at Devoxx presentation and what I've tried, so if I miss things, be keen to notify.

Telosys
  • Code generator
  • Based on DB
  • Performs enrichment via GUI(Eclispe plugin) in a phase called repository
  • Generates for a target framework (JEE, Ajax) developped by Telosys Team
  • Generates artefacts for entities (table) 
  • Metadata of template (name, ...) are store in text file
  • Use Velocity as a template rendering engine
Telosys goodies
  • JPA2 artefacts handle one2one relationship (not yet covered by minuteproject)
  • Telosys Plugin makes enrichment easy
Telosys neural
  • Targeting a specific 'Telosys Framework' solution as pros and cons
    • Pros 
      • fully customized
      • all in one inside IDE
    • Cons 
      • dev. burden on a team
      • no market place recognition
      • reusability of templates might be poor
Minuteproject
  • Code generator
  • Based on DB and WSDL based (next release: 0.7)
  • Performs enrichment via Configuration file or via a console
  • Generates for a range of market-place technologies
    • Spring/hibernate/ibatis/JPA1/JPA2
    • Openxava
    • Play
    • Grails
    • Roo
    • REST
    • Primefaces
    • FitNesse
    • ...
  • Generate for artifacts at 6 levels
    • Entity (tables/views)
    • Field
    • Package
    • Model
    • StoredProc
    • Application
  • Generated code can be updated and modifications are kept over consecutive generation
  • Metadata of template (name, 20 other attributes) are store in xml file 
  • Possibility to define convention:
    • Ex: view do not have PK but it is possible to define some individually or globally by applying a convention called 'apply-default-primary-key-otherwise-first-one'.
  • Use Velocity as a template rendering engine
Integration investigation tracks
Here are couple of feasible tracks under investigation:
  • Integrate Minuteproject tracks into Telosys
  • Add Telosys target as a MinuteProject 4 Telosys track
  • Add Telosys Plugin over Minuteproject generator