<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8723196641810122152</id><updated>2012-03-01T05:33:12.506-08:00</updated><category term='ibatis'/><category term='hibernate'/><category term='reverse-engineering'/><category term='jsf'/><category term='authentication'/><category term='web'/><category term='jaxb'/><category term='security'/><category term='soa'/><category term='spring-security'/><category term='maven'/><category term='metro'/><category term='methodology'/><category term='tomcat'/><category term='wsdl'/><category term='primefaces'/><category term='telosys'/><category term='portlet'/><category term='crud'/><category term='rest'/><category term='minuteproject'/><category term='querydsl'/><category term='grails'/><category term='liferay'/><category term='jaxws'/><category term='jooq'/><category term='ehcache'/><category term='agile'/><category term='unit test'/><category term='sql'/><category term='ejb'/><category term='rad'/><category term='spring'/><category term='play'/><category term='web2'/><category term='authorisation'/><category term='cdi'/><category term='openxava'/><category term='performance'/><category term='productivity'/><category term='jaxrs'/><category term='code generator'/><category term='fitnesse'/><category term='JEE'/><category term='vaadin'/><category term='jpa2'/><category term='database'/><category term='generator'/><title type='text'>minuteproject blog</title><subtitle type='html'>Follow me on twitter @minuteproject</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://minuteproject.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://minuteproject.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>florian</name><uri>http://www.blogger.com/profile/04083442568354390924</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>17</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8723196641810122152.post-8986582095776772039</id><published>2012-02-25T02:10:00.000-08:00</published><updated>2012-02-29T10:16:16.467-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='crud'/><category scheme='http://www.blogger.com/atom/ns#' term='liferay'/><category scheme='http://www.blogger.com/atom/ns#' term='rad'/><category scheme='http://www.blogger.com/atom/ns#' term='code generator'/><category scheme='http://www.blogger.com/atom/ns#' term='unit test'/><category scheme='http://www.blogger.com/atom/ns#' term='jooq'/><category scheme='http://www.blogger.com/atom/ns#' term='generator'/><title type='text'>Productivity by example: Liferay with JOOQ</title><content type='html'>This article shows how to use jOOQ for the Liferay data model.&lt;br /&gt;Minuteproject generates jOOQ artifacts for Liferay.&lt;br /&gt;The main interest of using minuteproject to generate jOOQ artefacts are&amp;nbsp; &lt;br /&gt;&lt;ul&gt;&lt;li&gt;Liferay database does not have any foreign key, but minuteproject is able to detect relationship based on patterns.&lt;/li&gt;&lt;li&gt;&amp;nbsp;Some DB naming convention might need to be adapted at Java level&lt;/li&gt;&lt;ul&gt;&lt;li&gt;DB tables ending with '_' will have underscore stripped&lt;/li&gt;&lt;li&gt;Column name ending with '_id' corresponding to PK or FK will have this particule stripped when not coliding with other variable&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Code is updatable, meaning that you can change part of it or entirely and consecutive generation will keep your alterations&lt;/li&gt;&lt;/ul&gt;For more information about the enrichment made on top of Liferay by minuteproject check another post targeting &lt;a href="http://minuteproject.blogspot.com/2011/12/productivity-by-example-liferay-reverse.html"&gt;Liferay with JPA2&lt;/a&gt;.&lt;br /&gt;Here the reverse-engineering targets jOOQ framework and the configuration mentions jOOQ track reference&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;Configuration&lt;/span&gt;&lt;br /&gt;mp-config-LIFERAY-JOOQ.xml&lt;span style="font-size: x-large;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;pre class="xml" name="code"&gt;&amp;lt;!DOCTYPE root&amp;gt;&lt;br /&gt;&amp;lt;generator-config&amp;gt;&lt;br /&gt; &amp;lt;configuration&amp;gt;&lt;br /&gt;  &amp;lt;conventions&amp;gt;&lt;br /&gt;   &amp;lt;target-convention type="enable-updatable-code-feature" /&amp;gt;&lt;br /&gt;  &amp;lt;/conventions&amp;gt;&lt;br /&gt;  &amp;lt;model name="liferay" version="1.0" package-root="net.sf.mp.demo"&amp;gt;&lt;br /&gt;   &amp;lt;data-model&amp;gt;&lt;br /&gt;    &amp;lt;driver name="mysql" version="5.1.16" groupId="mysql"&lt;br /&gt;     artifactId="mysql-connector-java"&amp;gt;&amp;lt;/driver&amp;gt;&lt;br /&gt;    &amp;lt;dataSource&amp;gt;&lt;br /&gt;     &amp;lt;driverClassName&amp;gt;org.gjt.mm.mysql.Driver&amp;lt;/driverClassName&amp;gt;&lt;br /&gt;     &amp;lt;url&amp;gt;jdbc:mysql://127.0.0.1:3306/lportal&amp;lt;/url&amp;gt;&lt;br /&gt;     &amp;lt;username&amp;gt;root&amp;lt;/username&amp;gt;&lt;br /&gt;     &amp;lt;password&amp;gt;mysql&amp;lt;/password&amp;gt;&lt;br /&gt;    &amp;lt;/dataSource&amp;gt;&lt;br /&gt;    &amp;lt;schema&amp;gt;lportal&amp;lt;/schema&amp;gt;&lt;br /&gt;    &amp;lt;primaryKeyPolicy oneGlobal="true"&amp;gt;&lt;br /&gt;     &amp;lt;primaryKeyPolicyPattern name="none"&amp;gt;&amp;lt;/primaryKeyPolicyPattern&amp;gt;&lt;br /&gt;    &amp;lt;/primaryKeyPolicy&amp;gt;&lt;br /&gt;   &amp;lt;/data-model&amp;gt;&lt;br /&gt;   &amp;lt;business-model&amp;gt;&lt;br /&gt;    &amp;lt;generation-condition&amp;gt;&lt;br /&gt;     &amp;lt;condition type="exclude" startsWith="QUARTZ"&amp;gt;&amp;lt;/condition&amp;gt;&lt;br /&gt;    &amp;lt;/generation-condition&amp;gt;&lt;br /&gt;    &amp;lt;enrichment&amp;gt;&lt;br /&gt;     &amp;lt;conventions&amp;gt;&lt;br /&gt;      &amp;lt;entity-naming-convention type="apply-strip-table-name-suffix"&lt;br /&gt;       pattern-to-strip="_" /&amp;gt;&lt;br /&gt;      &amp;lt;!-- manipulate the structure and entities BEFORE manipulating the &lt;br /&gt;       entities --&amp;gt;&lt;br /&gt;      &amp;lt;foreign-key-convention&lt;br /&gt;       type="autodetect-foreign-key-based-on-similarity-and-map"&lt;br /&gt;       column-ending="id" column-starting="" /&amp;gt;&lt;br /&gt;      &amp;lt;column-naming-convention type="apply-strip-column-name-suffix"&lt;br /&gt;       pattern-to-strip="ID" /&amp;gt;&lt;br /&gt;      &amp;lt;reference-naming-convention&lt;br /&gt;       type="apply-referenced-alias-when-no-ambiguity" is-to-plurialize="true" /&amp;gt;&lt;br /&gt;     &amp;lt;/conventions&amp;gt;&lt;br /&gt;    &amp;lt;/enrichment&amp;gt;&lt;br /&gt;   &amp;lt;/business-model&amp;gt;&lt;br /&gt;  &amp;lt;/model&amp;gt;&lt;br /&gt;  &amp;lt;targets&amp;gt;&lt;br /&gt;   &amp;lt;target refname="JOOQ" name="JOOQ" fileName="mp-template-config-JOOQ.xml"&lt;br /&gt;    outputdir-root="../../dev/JOOQ/liferay" templatedir-root="../../template/framework/jooq"&amp;gt;&lt;br /&gt;    &amp;lt;property name="jooq-version" value="2.0.4"&amp;gt;&amp;lt;/property&amp;gt;&lt;br /&gt;   &amp;lt;/target&amp;gt;&lt;br /&gt;   &amp;lt;target refname="LIB" fileName="mp-template-config-bsla-LIB-features.xml"&lt;br /&gt;    templatedir-root="../../template/framework/bsla"&amp;gt;&lt;br /&gt;   &amp;lt;/target&amp;gt;&lt;br /&gt;  &amp;lt;/targets&amp;gt;&lt;br /&gt; &amp;lt;/configuration&amp;gt;&lt;br /&gt;&amp;lt;/generator-config&amp;gt;&lt;/pre&gt;&lt;span style="font-size: x-large;"&gt;Execution&lt;/span&gt;&lt;br /&gt;Install Liferay mysql 6.0.6 running&lt;br /&gt;Download minuteproject&lt;br /&gt;Drop this config in &lt;mp_home&gt;/mywork/config&lt;/mp_home&gt;&lt;br /&gt;And execute model-generation.(sh/cmd) mp-config-LIFERAY-JOOQ.xml&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;Result&lt;span style="font-size: small;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;&lt;span style="font-size: small;"&gt;&lt;span style="font-size: large;"&gt;Artifacts &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;&lt;span style="font-size: small;"&gt;The resulting artefacts are&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size: x-large;"&gt;&lt;span style="font-size: small;"&gt;A maven project with following dependencies&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size: x-large;"&gt;&lt;span style="font-size: small;"&gt;jOOQ&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: x-large;"&gt;&lt;span style="font-size: small;"&gt;jUnit&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: x-large;"&gt;&lt;span style="font-size: small;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: x-large;"&gt;&lt;span style="font-size: small;"&gt;mysql drive&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;span style="font-size: x-large;"&gt;&lt;span style="font-size: small;"&gt;jOOQ artifacts&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size: x-large;"&gt;&lt;span style="font-size: small;"&gt;factory, keys, tables, records...&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;span style="font-size: x-large;"&gt;&lt;span style="font-size: small;"&gt;unit test&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;The artifacts are generated in &lt;mp_home&gt;/dev/JOOQ/liferay&lt;/mp_home&gt;&lt;/div&gt;&lt;span style="font-size: x-large;"&gt;&lt;span style="font-size: small;"&gt;If you build there will be a compilation error in jOOQ artifacts:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre style="font-family: inherit; margin: 0px;"&gt;&lt;span style="font-size: small;"&gt;Table 'expandotable' has a field call 'table' that collides with a Jooq method.&amp;nbsp;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="font-family: inherit; margin: 0px;"&gt;&lt;span style="font-size: small;"&gt;But just by altering the code to remove the compilation error and &lt;b&gt;flaging &lt;/b&gt;to take into account this modification:&lt;/span&gt;&lt;/pre&gt;&lt;pre style="font-family: inherit; margin: 0px;"&gt;&lt;span style="font-size: small;"&gt;In ExpandotableRecord&lt;/span&gt;&lt;span style="font-size: small;"&gt; &lt;/span&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;pre style="font-family: inherit; margin: 0px;"&gt;&lt;span style="font-size: small;"&gt;Change getTable into getTable_ &lt;/span&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;pre style="font-family: inherit; margin: 0px;"&gt;&lt;span style="font-size: small;"&gt;Exclude code from been overwritten: line 24 //MP-MANAGED-UPDATABLE-BEGINNING-&lt;b&gt;ENABLE&lt;/b&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre class="java" name="code"&gt; //MP-MANAGED-UPDATABLE-BEGINNING-ENABLE @jooq-record-pk-liferay@&lt;br /&gt; /**&lt;br /&gt;  * An uncommented item&lt;br /&gt;  * &lt;br /&gt;  * PRIMARY KEY&lt;br /&gt;  */&lt;br /&gt;    public void setTable(java.lang.Long value) {&lt;br /&gt;        setValue(net.sf.mp.demo.liferay.tables.Expandotable.__EXPANDOTABLE.TABLE, value);&lt;br /&gt;    }&lt;br /&gt; /**&lt;br /&gt;  * An uncommented item&lt;br /&gt;  * &lt;br /&gt;  * PRIMARY KEY&lt;br /&gt;  */&lt;br /&gt;    public java.lang.Long getTable_() {&lt;br /&gt;        return getValue(net.sf.mp.demo.liferay.tables.Expandotable.__EXPANDOTABLE.TABLE);&lt;br /&gt;    }&lt;br /&gt; //MP-MANAGED-UPDATABLE-ENDING&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div style="font-family: inherit;"&gt;&lt;u&gt;Remark&lt;/u&gt;: 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.&lt;/div&gt;&lt;div style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: inherit;"&gt;Eventually run: mvn clean package&lt;/div&gt;&lt;ul&gt;&lt;li&gt;A set of unittest are executed:&lt;/li&gt;&lt;ul&gt;&lt;li&gt;The default unit test consist to retrieve the first row of each entity. &lt;/li&gt;&lt;/ul&gt;&lt;li&gt;A JOOQ package is released&lt;/li&gt;&lt;/ul&gt;&lt;div style="font-family: inherit;"&gt;&lt;span style="font-size: large;"&gt;Code&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: inherit;"&gt;The code can be downloaded from minuteproject googlecode &lt;a href="http://code.google.com/p/minuteproject/downloads/detail?name=jooq-liferay-mp-0.8-release.zip&amp;amp;can=2&amp;amp;q=#makechanges"&gt;here&lt;/a&gt;.&lt;/div&gt;&lt;div style="font-family: inherit;"&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Sample&lt;/span&gt;&lt;br /&gt;Active record:&lt;br /&gt;Providing the Foreign key gives the ability to provide jOOQ records with some methods&lt;br /&gt;One to many&lt;br /&gt;//todo&lt;/div&gt;&lt;div style="font-family: inherit;"&gt;&lt;span style="font-size: x-large;"&gt;Testing &lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre class="java" name="code"&gt;/**&lt;br /&gt; * This class is generated by minuteproject 4 jOOQ&lt;br /&gt; */&lt;br /&gt;package net.sf.mp.demo.liferay.tables;&lt;br /&gt;&lt;br /&gt;import net.sf.mp.demo.liferay.tables.records.UserRecord;&lt;br /&gt;import net.sf.mp.demo.liferay.Liferay;&lt;br /&gt;import net.sf.mp.demo.liferay.Keys;&lt;br /&gt;&lt;br /&gt;import java.sql.Connection;&lt;br /&gt;import java.sql.DriverManager;&lt;br /&gt;import java.sql.SQLException;&lt;br /&gt;&lt;br /&gt;import net.sf.mp.demo.liferay.LiferayFactory;&lt;br /&gt;import static net.sf.mp.demo.liferay.tables.User.__USER;&lt;br /&gt;&lt;br /&gt;import org.jooq.Record;&lt;br /&gt;import org.jooq.Result;&lt;br /&gt;import org.junit.Test;&lt;br /&gt;&lt;br /&gt;//MP-MANAGED-ADDED-AREA-BEGINNING @import@&lt;br /&gt;import static net.sf.mp.demo.liferay.tables.Company.__COMPANY;&lt;br /&gt;import static net.sf.mp.demo.liferay.tables.Account.__ACCOUNT;&lt;br /&gt;//MP-MANAGED-ADDED-AREA-ENDING @import@&lt;br /&gt;&lt;br /&gt;//MP-MANAGED-ADDED-AREA-BEGINNING @class-annotation@&lt;br /&gt;//MP-MANAGED-ADDED-AREA-ENDING @class-annotation@&lt;br /&gt;@javax.annotation.Generated(value = { "http://www.jooq.org", "2.0.4" }, comments = "This class is generated by minuteproject 4 jOOQ")&lt;br /&gt;public class TestUser {&lt;br /&gt;&lt;br /&gt; @Test&lt;br /&gt; public void testUser() {&lt;br /&gt;  Connection conn = null;&lt;br /&gt;  String userName = "root";&lt;br /&gt;  String password = "mysql";&lt;br /&gt;  String url = "jdbc:mysql://127.0.0.1:3306/lportal";&lt;br /&gt;&lt;br /&gt;  try {&lt;br /&gt;   Class.forName("org.gjt.mm.mysql.Driver").newInstance();&lt;br /&gt;   conn = DriverManager.getConnection(url, userName, password);&lt;br /&gt;   LiferayFactory create = new LiferayFactory(conn);&lt;br /&gt;&lt;br /&gt;   // MP-MANAGED-UPDATABLE-BEGINNING-ENABLE&lt;br /&gt;   // @jooq-unittest-testUser-liferay@&lt;br /&gt;   // write your own tests, just set DISABLE to ENABLE in the comment&lt;br /&gt;   // above&lt;br /&gt;   // future generation will not erase your code ;)&lt;br /&gt;   Result&amp;lt;Record&amp;gt; result = create&lt;br /&gt;     .select(__USER.FIRSTNAME, __USER.LASTNAME, __COMPANY.WEB, __ACCOUNT.NAME)&lt;br /&gt;     .from(__USER).join(__COMPANY)&lt;br /&gt;     .on(__USER.COMPANY.equal(__COMPANY.COMPANY))&lt;br /&gt;     .join(__ACCOUNT)&lt;br /&gt;     .on(__COMPANY.ACCOUNT.equal(__ACCOUNT.ACCOUNT))&lt;br /&gt;     .where(__COMPANY.WEB.like("%ray.com"))&lt;br /&gt;     .orderBy(__USER.LASTNAME.asc().nullsFirst()).limit(10)&lt;br /&gt;     .fetch();&lt;br /&gt;   for (Record r : result) {&lt;br /&gt;    String firstname = r.getValue(__USER.FIRSTNAME);&lt;br /&gt;    String lastname = r.getValue(__USER.LASTNAME);&lt;br /&gt;    String web = r.getValue(__COMPANY.WEB);&lt;br /&gt;    String accountname = r.getValue(__ACCOUNT.NAME);&lt;br /&gt;&lt;br /&gt;    System.out.println(" firstname : " + firstname + " lastname : "&lt;br /&gt;      + lastname + " web : " + web + " accountname : "&lt;br /&gt;      + accountname);&lt;br /&gt;   }&lt;br /&gt;   // MP-MANAGED-UPDATABLE-ENDING&lt;br /&gt;&lt;br /&gt;  } catch (Exception e) {&lt;br /&gt;   e.printStackTrace();&lt;br /&gt;  } finally {&lt;br /&gt;   if (conn != null) {&lt;br /&gt;    try {&lt;br /&gt;     conn.close();&lt;br /&gt;    } catch (SQLException e) {&lt;br /&gt;     // TODO Auto-generated catch block&lt;br /&gt;     e.printStackTrace();&lt;br /&gt;    }&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; // MP-MANAGED-ADDED-AREA-BEGINNING @implementation@&lt;br /&gt; // MP-MANAGED-ADDED-AREA-ENDING @implementation@&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Giving at execution&lt;br /&gt;&lt;pre class="xml" name="code"&gt; firstname :  lastname :  web : liferay.com accountname : Liferay&lt;br /&gt; firstname : Joe lastname : Bloggs web : liferay.com accountname : Liferay&lt;br /&gt; firstname : Test lastname : DLC 1 web : liferay.com accountname : Liferay&lt;br /&gt; firstname : Test lastname : DLC 10 web : liferay.com accountname : Liferay&lt;br /&gt; firstname : Test lastname : DLC 2 web : liferay.com accountname : Liferay&lt;br /&gt; firstname : Test lastname : DLC 3 web : liferay.com accountname : Liferay&lt;br /&gt; firstname : Test lastname : DLC 4 web : liferay.com accountname : Liferay&lt;br /&gt; firstname : Test lastname : DLC 5 web : liferay.com accountname : Liferay&lt;br /&gt; firstname : Test lastname : DLC 6 web : liferay.com accountname : Liferay&lt;br /&gt; firstname : Test lastname : DLC 7 web : liferay.com accountname : Liferay&lt;br /&gt;&lt;/pre&gt;&lt;div style="font-family: inherit;"&gt;&lt;span style="font-size: x-large;"&gt;JOOQ quick review&lt;/span&gt;&lt;/div&gt;//todo&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Typesafe query speeds up the development process&lt;/li&gt;&lt;li&gt;No ORM&amp;nbsp;&lt;/li&gt;&lt;li&gt;Focus on CRUD and complexe query&amp;nbsp;&lt;/li&gt;&lt;li&gt;No configuration loading meaning fast to test&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8723196641810122152-8986582095776772039?l=minuteproject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://minuteproject.blogspot.com/feeds/8986582095776772039/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://minuteproject.blogspot.com/2012/02/productivity-by-example-liferay-with.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/8986582095776772039'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/8986582095776772039'/><link rel='alternate' type='text/html' href='http://minuteproject.blogspot.com/2012/02/productivity-by-example-liferay-with.html' title='Productivity by example: Liferay with JOOQ'/><author><name>florian</name><uri>http://www.blogger.com/profile/04083442568354390924</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8723196641810122152.post-2650526613831884805</id><published>2012-02-16T14:34:00.000-08:00</published><updated>2012-02-21T07:04:59.289-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><category scheme='http://www.blogger.com/atom/ns#' term='openxava'/><category scheme='http://www.blogger.com/atom/ns#' term='rad'/><category scheme='http://www.blogger.com/atom/ns#' term='minuteproject'/><category scheme='http://www.blogger.com/atom/ns#' term='spring-security'/><category scheme='http://www.blogger.com/atom/ns#' term='security'/><category scheme='http://www.blogger.com/atom/ns#' term='jpa2'/><category scheme='http://www.blogger.com/atom/ns#' term='authentication'/><category scheme='http://www.blogger.com/atom/ns#' term='authorisation'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Adding Spring-Security to Openxava</title><content type='html'>&lt;span style="font-size: x-large;"&gt;Introduction&lt;/span&gt;&lt;br /&gt;The purpose of this article is to see how to integrate Spring Security on top of Openxava standalone application.&lt;br /&gt;Openxava build portlets as well as standalone applications.&lt;br /&gt;When working with portlets, those are deployed on a portal such as Liferay which handles secured access by configuration. Meanwhile while working as standalone application you have to handle this functionality yourself.&lt;br /&gt;This page&amp;nbsp;will illustrate how to add spring security (authentication/authorisation) functionalities. The focus will be put the authorisations aspects since authorisation is often enterprise-environment specific.&lt;br /&gt;To demonstrate the integration, this article will use the &lt;a href="http://minuteproject.blogspot.com/2011/06/minuteproject-4-openxava-lazuly.html"&gt;minuteproject Lazuly showcase application generated for Openxava&lt;/a&gt;.&lt;br /&gt;The first part identifies and explains the actions to undertake.&lt;br /&gt;The second part explains what minuteproject can do to fasten your development by generated a customed spring-security integration for you Openxava application.&lt;br /&gt;Eventually a set of tests will ensure that the resulting application is correctly protected for URL direct access as well as content display.&lt;br /&gt;Furthermore, the integration is technologically &lt;b&gt;non-intruisive&lt;/b&gt;. You do not have to change Openxava code for it to work.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;Spring-Security Openxava integration&lt;/span&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;Technical Access&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;URL access&lt;/b&gt;&lt;br /&gt;The url pattern is the following&lt;br /&gt;http://servername&lt;servername&gt;:port/applicationcontext&lt;applicationcontext&gt;/xava/module.jsp?application=appName&lt;app&gt;&amp;amp;module=moduleName&lt;module&gt;&lt;/module&gt;&lt;/app&gt;&lt;/applicationcontext&gt;&lt;/servername&gt;&lt;br /&gt;given like that it is hard to protect.&lt;br /&gt;The module and application are passed as parameters.&lt;br /&gt;&lt;br /&gt;The URL has to be revisited with&lt;br /&gt;http://servername&lt;servername&gt;:port/applicationcontext&lt;applicationcontext&gt;/applicationPath/&lt;app&gt;module&lt;/app&gt;&lt;/applicationcontext&gt;&lt;/servername&gt;&lt;br /&gt;And the 'parameter' access are banned.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Enabling new URL access&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Add a servlet&lt;/b&gt;&lt;br /&gt;&lt;pre class="java" name="code"&gt;package net.sf.minuteproject.openxava.web.servlet;&lt;br /&gt;&lt;br /&gt;import java.io.*;&lt;br /&gt;import javax.servlet.*;&lt;br /&gt;import javax.servlet.http.*;&lt;br /&gt;&lt;br /&gt;public class ModuleHomeServlet extends HttpServlet {&lt;br /&gt; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {&lt;br /&gt;  RequestDispatcher dispatcher;&lt;br /&gt;  String [] uri = request.getRequestURI().split("/");&lt;br /&gt;  if (uri.length &amp;lt; 4) {&lt;br /&gt;   dispatcher = request.getRequestDispatcher("/xava/homeMenu.jsp");&lt;br /&gt;  } else {&lt;br /&gt;   dispatcher = request.getRequestDispatcher(&lt;br /&gt;   "/xava/home.jsp?application=" + uri[1] + "&amp;amp;module=" + uri[3]);&lt;br /&gt;  }&lt;br /&gt;  dispatcher.forward(request, response);&lt;br /&gt; }&lt;br /&gt; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {&lt;br /&gt;  doGet(request, response);&lt;br /&gt; }&lt;br /&gt;}&lt;/pre&gt;homeMenu.jsp is a page including a header with menu (to protect and whose menu link URL are correspond to the secured format) and a footer.&lt;br /&gt;&lt;b&gt;Add a servlet configuration&lt;/b&gt;&lt;br /&gt;Servlet configuration snippet done in Openxava servlets.xml.&lt;br /&gt;&lt;pre class="xml" name="code"&gt; &lt;servlet&gt;&lt;br /&gt; &amp;lt;servlet&amp;gt;&lt;br /&gt;  &amp;lt;servlet-name&amp;gt;moduleHome&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;  &amp;lt;servlet-class&amp;gt;net.sf.minuteproject.openxava.web.servlet.ModuleHomeServlet&amp;lt;/servlet-class&amp;gt;&lt;br /&gt; &amp;lt;/servlet&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;servlet-mapping&amp;gt;&lt;br /&gt;  &amp;lt;servlet-name&amp;gt;moduleHome&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;  &amp;lt;url-pattern&amp;gt;/MenuModules/*&amp;lt;/url-pattern&amp;gt;&lt;br /&gt; &amp;lt;/servlet-mapping&amp;gt;&lt;br /&gt; &lt;br /&gt;&lt;/servlet&gt;&lt;/pre&gt;This snippet will be package in war web.xml at build time by OpenXava ant script.&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Jsp access&lt;/b&gt;&lt;br /&gt;Prohibit any Openxava jsp access except the one of the menu&lt;br /&gt;&lt;br /&gt;To do that add an spring applicationContext-security.xml in you classpath (ex: Openxava src folder).&lt;br /&gt;&lt;pre class="java" name="code"&gt;&amp;lt;b:beans xmlns="http://www.springframework.org/schema/security"&lt;br /&gt;...&lt;br /&gt;    &amp;lt;http realm="conference Realm"&amp;gt;&lt;br /&gt;        &amp;lt;!-- default url --&amp;gt;&lt;br /&gt;  &amp;lt;intercept-url pattern="/xava/homeMenu.jsp" access="ROLE_APPLICATION_USER"/&amp;gt;        &lt;br /&gt;        &amp;lt;intercept-url pattern="/xava/**/*.jsp" access="ROLE_NOT_PRESENT"/&amp;gt;&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;This means that all path after xava will be accessible (ex: css...) safe jsp expect one homeMenu.jsp is available to all registered user (ie having role ROLE_APPLICATION_USER cf attribution at authorisation part further).&lt;br /&gt;Of course ensure that the role ROLE_NOT_PRESENT is really not present in your app.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Business Access&lt;/b&gt;&lt;br /&gt;The idea is to give CRUD access on a entity base on role.&lt;br /&gt;&lt;b&gt;Define roles and UC&lt;/b&gt;&lt;br /&gt;To be more explicit, I define 3 roles with their scope.&lt;br /&gt;Administrator can administrate ROLE and COUNTRY entities&lt;br /&gt;Application_user can manage all the other conference related tables safe the master data table mentionned above&lt;br /&gt;Reviewer can access to the statistic views but not the administration.&lt;br /&gt;Both reviewer and Administrator can do what Application_user can do.&lt;br /&gt;&lt;br /&gt;In&amp;nbsp;applicationContext-security.xml the role can be mapped to specific URLs&lt;br /&gt;&lt;pre class="java" name="code"&gt;&amp;lt;b:beans xmlns="http://www.springframework.org/schema/security"&lt;br /&gt;....&lt;br /&gt;    &amp;lt;http realm="conference Realm"&amp;gt;&lt;br /&gt;   &amp;lt;!-- secured country --&amp;gt;&lt;br /&gt;        &amp;lt;intercept-url pattern="/MenuModules/Country" access="ROLE_ADMINISTRATOR"/&amp;gt;&lt;br /&gt;  &amp;lt;!-- secured role --&amp;gt;&lt;br /&gt;        &amp;lt;intercept-url pattern="/MenuModules/Role" access="ROLE_ADMINISTRATOR"/&amp;gt;&lt;br /&gt; &amp;lt;!-- secured stat_mb_by_role --&amp;gt;&lt;br /&gt;        &amp;lt;intercept-url pattern="/MenuModules/MemberPerRoleCountryAndConference" access="ROLE_REVIEWER"/&amp;gt;&lt;br /&gt; &amp;lt;!-- secured stat_mb_per_ctry_conf --&amp;gt;&lt;br /&gt;        &amp;lt;intercept-url pattern="/MenuModules/MemberPerCountryAndConference" access="ROLE_REVIEWER"/&amp;gt;&lt;br /&gt;  &amp;lt;intercept-url pattern="/MenuModules/**" access="ROLE_APPLICATION_USER"/&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Impact of the roles access on your model modal navigation&lt;/b&gt;&lt;br /&gt;Be coherent&lt;br /&gt;As said before 'the CRUD access on a entity is role based' but the affectation mechanism has to reflect that.&lt;br /&gt;OpenXava has annotation to create an entity from another one. It is then logical that we cannot create entity B from entity A, if we do not have CRUD rights on entity B.&lt;br /&gt;The mechanism will consist in this case of affectation only with search functionalities.&lt;br /&gt;In our scenario it means that a user with 'application_user' only can select a country but can not create any (no create or update icons available).&lt;br /&gt;&lt;br /&gt;It is also true at the menu level, a user is entitled to see only its menu items corresponding to its profile. &lt;br /&gt;Here the menu is done in jsp.&lt;br /&gt;To secure the access you can wrap to code to secure with taglib code coming with spring security or add a little taglib such as the following isUserInRole.tag located in web/WEB-INF/tags/common&lt;br /&gt;&lt;pre class="xml" name="code"&gt;&amp;lt;%@ attribute name="role" required="true" %&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;%!&lt;br /&gt;&lt;br /&gt;    public boolean hasRole(javax.servlet.http.HttpServletRequest request, String role) {&lt;br /&gt;        return request.isUserInRole(role) || &lt;br /&gt;            request.isUserInRole(role.toUpperCase()) || &lt;br /&gt;            request.isUserInRole("ROLE_"+role.toUpperCase());&lt;br /&gt;    }&lt;br /&gt;%&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;%&lt;br /&gt;     String [] roles = role.split(",");&lt;br /&gt;     int length = roles.length;&lt;br /&gt;     boolean isInRole = false;&lt;br /&gt;     for (int i = 0; i &amp;lt; length;i++) {&lt;br /&gt;      String role = (roles[i]);&lt;br /&gt;         if(hasRole(request, role)) {&lt;br /&gt;             isInRole = true;&lt;br /&gt;             break;&lt;br /&gt;         }   &lt;br /&gt;     }&lt;br /&gt;    if(isInRole) {&lt;br /&gt;%&amp;gt;&lt;br /&gt;        &amp;lt;jsp:doBody/&amp;gt;&lt;br /&gt;&amp;lt;%        &lt;br /&gt;    }&lt;br /&gt;%&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Wrap the code to protect here the administrator menu and each menu item&lt;br /&gt;&lt;pre class="xml" name="code"&gt;&amp;lt;mp:isUserInRole role="administrator"&amp;gt;&lt;br /&gt;    &amp;lt;li class="topitem"&amp;gt;&lt;br /&gt;      &amp;lt;a href="#" onclick="return false;"&amp;gt;&lt;br /&gt;      Administration&lt;br /&gt;      &amp;lt;/a&amp;gt;&lt;br /&gt;   &amp;lt;ul class="submenu"&amp;gt;&lt;br /&gt;&amp;lt;mp:isUserInRole role="administrator"&amp;gt;&lt;br /&gt;        &amp;lt;li&amp;gt;&amp;lt;a href="/conference/MenuModules/Country" &amp;gt;Country&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;lt;/mp:isUserInRole&amp;gt;&lt;br /&gt;&amp;lt;mp:isUserInRole role="administrator"&amp;gt;&lt;br /&gt;        &amp;lt;li&amp;gt;&amp;lt;a href="/conference/MenuModules/Role" &amp;gt;Role&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;lt;/mp:isUserInRole&amp;gt;&lt;br /&gt;   &amp;lt;/ul&amp;gt;&lt;br /&gt; &amp;lt;/li&amp;gt;&lt;br /&gt;&amp;lt;/mp:isUserInRole&amp;gt; &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Authentication/Authorisation&lt;/span&gt;&lt;br /&gt;For the user to operate, he must be authenticated and authorised (moment where his role profile is loaded granting him with business access rights). I use an simple authentication and authorisation based a DB information.&lt;br /&gt;&lt;u&gt;Of course you are not supposed to use that in production ;)&lt;/u&gt;&lt;br /&gt;In applicationContext-security.xml add the following snippet.&lt;br /&gt;&lt;pre class="xml" name="code"&gt;    &amp;lt;authentication-manager&amp;gt;&lt;br /&gt;      &amp;lt;authentication-provider&amp;gt;&lt;br /&gt;        &amp;lt;jdbc-user-service &lt;br /&gt;          data-source-ref="dataSource" &lt;br /&gt;          users-by-username-query="SELECT username,password,active FROM user_authentication WHERE username = ?"&lt;br /&gt;          authorities-by-username-query="SELECT username,role FROM user_authorisation WHERE username = ?" &lt;br /&gt;          /&amp;gt;&lt;br /&gt;      &amp;lt;/authentication-provider&amp;gt; &lt;br /&gt;    &amp;lt;/authentication-manager&amp;gt;  &lt;br /&gt;    &amp;lt;b:bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"&amp;gt;&lt;br /&gt;        &amp;lt;b:property name="jndiName"&amp;gt;&amp;lt;b:value&amp;gt;java:comp/env/jdbc/conferenceDS&amp;lt;/b:value&amp;gt;&amp;lt;/b:property&amp;gt;&lt;br /&gt;    &amp;lt;/b:bean&amp;gt;  &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Both authorisation and authentication queries have to be valid.&lt;br /&gt;Here, they are done on top of views, which means that you have to implement 2 views: user_authentication and user_authorisation.&lt;br /&gt;The datasource is the same as the one of the Openxava application&lt;br /&gt;View gives you flexibility because if you have indirection level of granularity such as (user-role-permission), your view can associate user to role&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Authentication flow&lt;/span&gt;&lt;br /&gt;Eventually you need to handle an authentication flow composed of&lt;br /&gt;&lt;ul&gt;&lt;li&gt;welcome page&lt;/li&gt;&lt;li&gt;login page&lt;/li&gt;&lt;li&gt;access denied page&lt;/li&gt;&lt;li&gt;logout link &lt;/li&gt;&lt;/ul&gt;The flow is handled by&amp;nbsp;applicationContext-security.xml&lt;br /&gt;Add the following snippet.&lt;br /&gt;&lt;pre class="xml" name="code"&gt;    &amp;lt;authentication-manager&amp;gt;&lt;br /&gt;    &amp;lt;http realm="conference Realm"&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;intercept-url pattern="/" access="IS_AUTHENTICATED_ANONYMOUSLY"/&amp;gt;&lt;br /&gt;        &amp;lt;intercept-url pattern="/index.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY"/&amp;gt;&lt;br /&gt;        &amp;lt;intercept-url pattern="/hello.htm" access="IS_AUTHENTICATED_ANONYMOUSLY"/&amp;gt;&lt;br /&gt;        &amp;lt;intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/&amp;gt;&lt;br /&gt;        &amp;lt;form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?login_error=1"/&amp;gt;&lt;br /&gt;        &amp;lt;http-basic/&amp;gt;&lt;br /&gt;        &amp;lt;logout logout-success-url="/index.jsp"/&amp;gt;&lt;br /&gt;        &amp;lt;remember-me /&amp;gt;&lt;br /&gt;        &amp;lt;access-denied-handler error-page="/accessDenied.jsp"/&amp;gt; &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Login.jsp&lt;/b&gt; is strongly inspired by spring petclinic sample&lt;br /&gt;&lt;pre class="html" name="code"&gt;&amp;lt;%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %&amp;gt;&lt;br /&gt;&amp;lt;%@ page pageEncoding="UTF-8" %&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt;  &amp;lt;head&amp;gt;&lt;br /&gt;    &amp;lt;title&amp;gt;Login&amp;lt;/title&amp;gt;&lt;br /&gt;  &amp;lt;/head&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;body onload="document.f.j_username.focus();"&amp;gt;&lt;br /&gt;    &amp;lt;h1&amp;gt;Login test&amp;lt;/h1&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;p&amp;gt;Locale is: &amp;lt;%= request.getLocale() %&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;    &amp;lt;%-- this form-login-page form is also used as the&lt;br /&gt;         form-error-page to ask for a login again.&lt;br /&gt;         --%&amp;gt;&lt;br /&gt;    &amp;lt;c:if test="${ not empty param.login_error}"&amp;gt;&lt;br /&gt;      &amp;lt;font color="red"&amp;gt;&lt;br /&gt;        Your login attempt was not successful, try again.&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;        Reason: &amp;lt;c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}"/&amp;gt;.&lt;br /&gt;      &amp;lt;/font&amp;gt;&lt;br /&gt;    &amp;lt;/c:if&amp;gt;   &lt;br /&gt;&lt;br /&gt;    &amp;lt;form name="f" action="&amp;lt;c:url value='j_spring_security_check'/&amp;gt;" method="POST"&amp;gt;&lt;br /&gt;      &amp;lt;table&amp;gt;&lt;br /&gt;        &amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;User:&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;lt;input type='text' name='j_username' value='&amp;lt;c:if test="${ not empty param.login_error }"&amp;gt;&amp;lt;c:out value="${SPRING_SECURITY_LAST_USERNAME}"/&amp;gt;&amp;lt;/c:if&amp;gt;'/&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;        &amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;Password:&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;lt;input type='password' name='j_password'&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;        &amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;input type="checkbox" name="_spring_security_remember_me"&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Don't ask for my password for two weeks&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;tr&amp;gt;&amp;lt;td colspan='2'&amp;gt;&amp;lt;input name="submit" type="submit"&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;        &amp;lt;tr&amp;gt;&amp;lt;td colspan='2'&amp;gt;&amp;lt;input name="reset" type="reset"&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;      &amp;lt;/table&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;/form&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;index.jsp&lt;/b&gt;&lt;br /&gt;&lt;pre class="html" name="code"&gt;&amp;lt;html&amp;gt;&lt;br /&gt;  &amp;lt;head&amp;gt;&lt;br /&gt;    &amp;lt;title&amp;gt;Welcome to Conference&amp;lt;/title&amp;gt;&lt;br /&gt;  &amp;lt;/head&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;body&amp;gt;&lt;br /&gt;    &amp;lt;h1&amp;gt;Welcome to Conference&amp;lt;/h1&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;a href="/conference/xava/homeMenu.jsp"&amp;gt;login&amp;lt;/a&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;accessDenied.jsp&lt;/b&gt;&lt;br /&gt;&lt;pre class="html" name="code"&gt;Access denied!&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Not to forget a logout functionality here added on the menu&lt;br /&gt;&lt;br /&gt;&lt;pre class="html" name="code"&gt;     &amp;lt;span id="logout"&amp;gt;&amp;lt;a href="../j_spring_security_logout"&amp;gt;Logoff&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Spring security dependencies&lt;/span&gt;&lt;br /&gt;Add spring security jars into web/WEB-INF/lib&lt;br /&gt;&lt;br /&gt;spring-aop-3.0.4.RELEASE.jar&lt;br /&gt;spring-asm-3.0.4.RELEASE.jar&lt;br /&gt;spring-beans-3.0.4.RELEASE.jar&lt;br /&gt;spring-context-3.0.4.RELEASE.jar&lt;br /&gt;spring-core-3.0.4.RELEASE.jar&lt;br /&gt;spring-expression-3.0.4.RELEASE.jar&lt;br /&gt;spring-jdbc-3.0.4.RELEASE.jar&lt;br /&gt;spring-security-acl-2.0.3.jar&lt;br /&gt;spring-security-config-3.1.0.M1.jar&lt;br /&gt;spring-security-core-2.0.3.jar&lt;br /&gt;spring-security-core-3.1.0.M1.jar&lt;br /&gt;spring-security-core-tiger-2.0.3.jar&lt;br /&gt;spring-security-taglibs-2.0.3.jar&lt;br /&gt;spring-security-web-3.1.0.M1.jar&lt;br /&gt;spring-tx-3.0.4.RELEASE.jar&lt;br /&gt;spring-web-3.0.4.RELEASE.jar&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Spring security context&lt;/span&gt;&lt;br /&gt;Spring security context had been mentioned at different level, here is the complete version&lt;br /&gt;&lt;pre class="html" name="code"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt; &lt;br /&gt;&lt;br /&gt;&amp;lt;b:beans xmlns="http://www.springframework.org/schema/security" &lt;br /&gt;    xmlns:b="http://www.springframework.org/schema/beans" &lt;br /&gt;    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" &lt;br /&gt;    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd&lt;br /&gt;                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd"&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;authentication-manager&amp;gt; &lt;br /&gt;      &amp;lt;authentication-provider&amp;gt; &lt;br /&gt;        &amp;lt;jdbc-user-service &lt;br /&gt;          data-source-ref="dataSource" &lt;br /&gt;          users-by-username-query="SELECT username,password,active FROM user_authentication WHERE username = ?" &lt;br /&gt;          authorities-by-username-query="SELECT username,role FROM user_authorisation WHERE username = ?" &lt;br /&gt;          /&amp;gt; &lt;br /&gt;      &amp;lt;/authentication-provider&amp;gt; &lt;br /&gt;    &amp;lt;/authentication-manager&amp;gt;  &lt;br /&gt;    &lt;br /&gt;    &amp;lt;http realm="conference Realm"&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;intercept-url pattern="/" access="IS_AUTHENTICATED_ANONYMOUSLY"/&amp;gt; &lt;br /&gt;        &amp;lt;intercept-url pattern="/index.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY"/&amp;gt; &lt;br /&gt;        &amp;lt;intercept-url pattern="/hello.htm" access="IS_AUTHENTICATED_ANONYMOUSLY"/&amp;gt; &lt;br /&gt;        &amp;lt;intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;!-- default url --&amp;gt; &lt;br /&gt;&lt;br /&gt;                &amp;lt;intercept-url pattern="/xava/homeMenu.jsp" access="ROLE_APPLICATION_USER"/&amp;gt;        &lt;br /&gt;        &amp;lt;intercept-url pattern="/xava/**/*.jsp" access="ROLE_NOT_PRESENT"/&amp;gt;  &lt;br /&gt;                &lt;br /&gt;                &amp;lt;!-- secured country --&amp;gt; &lt;br /&gt;        &amp;lt;intercept-url pattern="/MenuModules/Country" access="ROLE_ADMINISTRATOR"/&amp;gt; &lt;br /&gt;                &amp;lt;!-- secured role --&amp;gt; &lt;br /&gt;        &amp;lt;intercept-url pattern="/MenuModules/Role" access="ROLE_ADMINISTRATOR"/&amp;gt; &lt;br /&gt;        &amp;lt;!-- secured stat_mb_by_role --&amp;gt; &lt;br /&gt;        &amp;lt;intercept-url pattern="/MenuModules/MemberPerRoleCountryAndConference" access="ROLE_REVIEWER"/&amp;gt; &lt;br /&gt;        &amp;lt;!-- secured stat_mb_per_ctry_conf --&amp;gt; &lt;br /&gt;        &amp;lt;intercept-url pattern="/MenuModules/MemberPerCountryAndConference" access="ROLE_REVIEWER"/&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;intercept-url pattern="/MenuModules/**" access="ROLE_APPLICATION_USER"/&amp;gt; &lt;br /&gt;                &lt;br /&gt;        &amp;lt;form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?login_error=1"/&amp;gt; &lt;br /&gt;        &amp;lt;http-basic/&amp;gt; &lt;br /&gt;        &amp;lt;logout logout-success-url="/index.jsp"/&amp;gt; &lt;br /&gt;        &amp;lt;remember-me /&amp;gt; &lt;br /&gt;        &amp;lt;access-denied-handler error-page="/accessDenied.jsp"/&amp;gt; &lt;br /&gt;    &amp;lt;/http&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;b:bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"&amp;gt; &lt;br /&gt;        &amp;lt;b:property name="jndiName"&amp;gt;&amp;lt;b:value&amp;gt;java:comp/env/jdbc/conferenceDS&amp;lt;/b:value&amp;gt;&amp;lt;/b:property&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;/b:bean&amp;gt;    &lt;br /&gt;         &lt;br /&gt;&amp;lt;/b:beans&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Reference the context&lt;/b&gt;&lt;br /&gt;Openxava listeners.xml is the place where you can set web.xml-snippets to be package in web.xml at Openxava build time&lt;br /&gt;Add the following snippet&lt;br /&gt;&lt;pre class="html" name="code"&gt; &amp;lt;listener&amp;gt;&lt;br /&gt;        &amp;lt;listener-class&amp;gt;org.springframework.web.context.ContextLoaderListener&amp;lt;/listener-class&amp;gt;&lt;br /&gt;    &amp;lt;/listener&amp;gt;&lt;br /&gt;     &lt;br /&gt;    &amp;lt;context-param&amp;gt;&lt;br /&gt;        &amp;lt;param-name&amp;gt;contextConfigLocation&amp;lt;/param-name&amp;gt;&lt;br /&gt;        &amp;lt;param-value&amp;gt;&lt;br /&gt;            classpath:applicationContext-security.xml&lt;br /&gt;        &amp;lt;/param-value&amp;gt;&lt;br /&gt;    &amp;lt;/context-param&amp;gt; &lt;br /&gt; &lt;br /&gt; &amp;lt;filter&amp;gt;&lt;br /&gt;   &amp;lt;filter-name&amp;gt;springSecurityFilterChain&amp;lt;/filter-name&amp;gt;&lt;br /&gt;   &amp;lt;filter-class&amp;gt;&lt;br /&gt;     org.springframework.web.filter.DelegatingFilterProxy&lt;br /&gt;   &amp;lt;/filter-class&amp;gt;&lt;br /&gt; &amp;lt;/filter&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;filter-mapping&amp;gt;&lt;br /&gt;   &amp;lt;filter-name&amp;gt;springSecurityFilterChain&amp;lt;/filter-name&amp;gt;&lt;br /&gt;   &amp;lt;url-pattern&amp;gt;/*&amp;lt;/url-pattern&amp;gt;&lt;br /&gt; &amp;lt;/filter-mapping&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;The minuteproject way&amp;nbsp;&lt;/span&gt;&lt;br /&gt;Doing the integration can be time consuming.As you can notice there is some effort to have the code compliant for a webapp here Openxava to be bodyguard by Spring-Security.&lt;br /&gt;Meanwhile when dealing with data centric application, this knowledge can be crystalized to be instantly available.&lt;br /&gt;&lt;b&gt;Because...there is an underlying concept that guides our choice and lead to best pratices.&lt;/b&gt;&lt;br /&gt;It is one thing to execute them, it is another to state it. &lt;br /&gt;The question is how do we specify which entity to access and to which role. The idea is to express with simplicity the relationship between role or permissionand action.&lt;br /&gt;In our case the actions are :&lt;br /&gt;&lt;ul&gt;&lt;li&gt;a full CRUD&lt;/li&gt;&lt;li&gt;an affectation mechanism &lt;/li&gt;&lt;/ul&gt;The full CRUD is associated to a specific role.&lt;br /&gt;The affection (linkage of an entity from another by search) is when to entities are linked but not all the role of the main entities are the same as the roles of the target. Otherwise affection goes with creation and update.&lt;br /&gt;&lt;br /&gt;And the roles are:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Administrator&lt;/li&gt;&lt;li&gt;Application_user&lt;/li&gt;&lt;li&gt;Reviewer&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;Now it is time for a primary school exercice&lt;/b&gt;&lt;br /&gt;If you represent an entity-relationship diagram, you should see boxes and links. Boxes for entities and links for relationships.&lt;br /&gt;Give each role/permission a color.&lt;br /&gt;Paint all the boxes that are full CRUD with the corresponding role color... Yes, you may paint the same box twice (resulting is color combination).&lt;br /&gt;&lt;b&gt;The result gives you the Color access spectrum of your DB.&lt;/b&gt;&lt;br /&gt;Of course, we can further decline the gradient with other function (read-only, controller specific...)&lt;br /&gt;But the underlying idea is evident.&lt;br /&gt;&lt;br /&gt;What Minuteproject allows you to do it by enriching your model with this color spectrum at the entity level or at the package level. This enables you to work with concept only closed to UC agnostic of technology implementations.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Minuteproject configuration snippet&lt;/span&gt;&lt;br /&gt;&lt;pre class="xml" name="code"&gt;&amp;lt;package name="admin" alias="Administration"&amp;gt;&lt;br /&gt; &amp;lt;security-color roles="administrator" /&amp;gt;&lt;br /&gt;&amp;lt;/package&amp;gt;&lt;br /&gt;&amp;lt;package name="statistics"&amp;gt;&lt;br /&gt; &amp;lt;security-color roles="reviewer" /&amp;gt;&lt;br /&gt;&amp;lt;/package&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Generation&lt;/span&gt;&lt;br /&gt;Minuteproject configuration full&lt;br /&gt;The configuration is similar to lazuly show case enhanced with security aspects&lt;br /&gt;&lt;pre class="xml" name="code"&gt;&amp;lt;!DOCTYPE root&amp;gt;&lt;br /&gt;&amp;lt;generator-config&amp;gt;&lt;br /&gt; &amp;lt;configuration&amp;gt;&lt;br /&gt;  &amp;lt;model name="conference" version="1.0" package-root="net.sf.mp.demo"&amp;gt;&lt;br /&gt;   &amp;lt;data-model&amp;gt;&lt;br /&gt;    &amp;lt;driver name="mysql" version="5.1.16" groupId="mysql"&lt;br /&gt;     artifactId="mysql-connector-java"&amp;gt;&amp;lt;/driver&amp;gt;&lt;br /&gt;    &amp;lt;dataSource&amp;gt;&lt;br /&gt;     &amp;lt;driverClassName&amp;gt;org.gjt.mm.mysql.Driver&amp;lt;/driverClassName&amp;gt;&lt;br /&gt;     &amp;lt;url&amp;gt;jdbc:mysql://127.0.0.1:3306/conference&amp;lt;/url&amp;gt;&lt;br /&gt;     &amp;lt;username&amp;gt;root&amp;lt;/username&amp;gt;&lt;br /&gt;     &amp;lt;password&amp;gt;mysql&amp;lt;/password&amp;gt;&lt;br /&gt;    &amp;lt;/dataSource&amp;gt;&lt;br /&gt;    &amp;lt;!-- for Oracle and DB2 please set the schema &amp;lt;schema&amp;gt; &amp;lt;/schema&amp;gt; --&amp;gt;&lt;br /&gt;    &amp;lt;primaryKeyPolicy oneGlobal="true"&amp;gt;&lt;br /&gt;     &amp;lt;primaryKeyPolicyPattern name="autoincrementPattern"&amp;gt;&amp;lt;/primaryKeyPolicyPattern&amp;gt;&lt;br /&gt;    &amp;lt;/primaryKeyPolicy&amp;gt;&lt;br /&gt;   &amp;lt;/data-model&amp;gt;&lt;br /&gt;   &amp;lt;business-model&amp;gt;&lt;br /&gt;    &amp;lt;generation-condition&amp;gt;&lt;br /&gt;     &amp;lt;condition type="exclude" startsWith="user_"&amp;gt;&amp;lt;/condition&amp;gt;&lt;br /&gt;    &amp;lt;/generation-condition&amp;gt;&lt;br /&gt;    &amp;lt;business-package default="conference"&amp;gt;&lt;br /&gt;     &amp;lt;condition type="package" startsWith="STAT" result="statistics"&amp;gt;&amp;lt;/condition&amp;gt;&lt;br /&gt;     &amp;lt;condition type="package" startsWith="COUNTRY" result="admin"&amp;gt;&amp;lt;/condition&amp;gt;&lt;br /&gt;     &amp;lt;condition type="package" startsWith="ROLE" result="admin"&amp;gt;&amp;lt;/condition&amp;gt;&lt;br /&gt;    &amp;lt;/business-package&amp;gt;&lt;br /&gt;    &amp;lt;enrichment&amp;gt;&lt;br /&gt;     &amp;lt;conventions&amp;gt;&lt;br /&gt;      &amp;lt;column-naming-convention type="apply-strip-column-name-suffix"&lt;br /&gt;       pattern-to-strip="_ID" /&amp;gt;&lt;br /&gt;      &amp;lt;reference-naming-convention&lt;br /&gt;       type="apply-referenced-alias-when-no-ambiguity" is-to-plurialize="true" /&amp;gt;&lt;br /&gt;     &amp;lt;/conventions&amp;gt;&lt;br /&gt;     &amp;lt;package name="admin" alias="Administration"&amp;gt;&lt;br /&gt;      &amp;lt;security-color roles="administrator" /&amp;gt;&lt;br /&gt;     &amp;lt;/package&amp;gt;&lt;br /&gt;     &amp;lt;package name="statistics"&amp;gt;&lt;br /&gt;      &amp;lt;security-color roles="reviewer" /&amp;gt;&lt;br /&gt;     &amp;lt;/package&amp;gt;&lt;br /&gt;     &amp;lt;entity name="COUNTRY" content-type="reference-data"&amp;gt;&lt;br /&gt;      &amp;lt;semantic-reference&amp;gt;&lt;br /&gt;       &amp;lt;sql-path path="NAME" /&amp;gt;&lt;br /&gt;      &amp;lt;/semantic-reference&amp;gt;&lt;br /&gt;     &amp;lt;/entity&amp;gt;&lt;br /&gt;     &amp;lt;entity name="CONFERENCE_MEMBER"&amp;gt;&lt;br /&gt;      &amp;lt;semantic-reference&amp;gt;&lt;br /&gt;       &amp;lt;sql-path path="FIRST_NAME" /&amp;gt;&lt;br /&gt;       &amp;lt;sql-path path="LAST_NAME" /&amp;gt;&lt;br /&gt;      &amp;lt;/semantic-reference&amp;gt;&lt;br /&gt;      &amp;lt;field name="STATUS"&amp;gt;&lt;br /&gt;       &amp;lt;property tag="checkconstraint" alias="conference_member_status"&amp;gt;&lt;br /&gt;        &amp;lt;property name="PENDING" value="PENDING" /&amp;gt;&lt;br /&gt;        &amp;lt;property name="ACTIVE" value="ACTIVE" /&amp;gt;&lt;br /&gt;       &amp;lt;/property&amp;gt;&lt;br /&gt;      &amp;lt;/field&amp;gt;&lt;br /&gt;      &amp;lt;field name="EMAIL"&amp;gt;&lt;br /&gt;       &amp;lt;stereotype stereotype="EMAIL" /&amp;gt;&lt;br /&gt;      &amp;lt;/field&amp;gt;&lt;br /&gt;     &amp;lt;/entity&amp;gt;&lt;br /&gt;     &amp;lt;entity name="SPEAKER"&amp;gt;&lt;br /&gt;      &amp;lt;field name="BIO"&amp;gt;&lt;br /&gt;       &amp;lt;stereotype stereotype="HTML_TEXT" /&amp;gt;&lt;br /&gt;      &amp;lt;/field&amp;gt;&lt;br /&gt;      &amp;lt;field name="PHOTO"&amp;gt;&lt;br /&gt;       &amp;lt;stereotype stereotype="PHOTO" /&amp;gt;&lt;br /&gt;      &amp;lt;/field&amp;gt;&lt;br /&gt;      &amp;lt;field name="WEB_SITE_URL"&amp;gt;&lt;br /&gt;       &amp;lt;stereotype stereotype="WEBURL" /&amp;gt;&lt;br /&gt;      &amp;lt;/field&amp;gt;&lt;br /&gt;     &amp;lt;/entity&amp;gt;&lt;br /&gt;     &amp;lt;entity name="PRESENTATION"&amp;gt;&lt;br /&gt;      &amp;lt;field name="STATUS"&amp;gt;&lt;br /&gt;       &amp;lt;property tag="checkconstraint" alias="presentation_status"&amp;gt;&lt;br /&gt;        &amp;lt;property name="PROPOSAL" value="PROPOSAL" /&amp;gt;&lt;br /&gt;        &amp;lt;property name="ACTIVE" value="ACTIVE" /&amp;gt;&lt;br /&gt;       &amp;lt;/property&amp;gt;&lt;br /&gt;      &amp;lt;/field&amp;gt;&lt;br /&gt;     &amp;lt;/entity&amp;gt;&lt;br /&gt;     &amp;lt;entity name="SPONSOR"&amp;gt;&lt;br /&gt;      &amp;lt;field name="STATUS"&amp;gt;&lt;br /&gt;       &amp;lt;property tag="checkconstraint" alias="sponsor_status"&amp;gt;&lt;br /&gt;        &amp;lt;property name="PENDING" value="PENDING" /&amp;gt;&lt;br /&gt;        &amp;lt;property name="ACTIVE" value="ACTIVE" /&amp;gt;&lt;br /&gt;       &amp;lt;/property&amp;gt;&lt;br /&gt;      &amp;lt;/field&amp;gt;&lt;br /&gt;      &amp;lt;field name="PRIVILEGE_TYPE"&amp;gt;&lt;br /&gt;       &amp;lt;property tag="checkconstraint" alias="sponsor_privilege"&amp;gt;&lt;br /&gt;        &amp;lt;property name="GOLDEN" value="Golden" /&amp;gt;&lt;br /&gt;        &amp;lt;property name="SILVER" value="Silver" /&amp;gt;&lt;br /&gt;        &amp;lt;property name="BRONZE" value="Bronze" /&amp;gt;&lt;br /&gt;       &amp;lt;/property&amp;gt;&lt;br /&gt;      &amp;lt;/field&amp;gt;&lt;br /&gt;     &amp;lt;/entity&amp;gt;&lt;br /&gt;     &amp;lt;!-- views --&amp;gt;&lt;br /&gt;     &amp;lt;entity name="stat_mb_per_ctry_conf" alias="MEMBER_PER_COUNTRY_AND_CONFERENCE"&amp;gt;&lt;br /&gt;      &amp;lt;virtual-primary-key isRealPrimaryKey="true"&amp;gt;&lt;br /&gt;       &amp;lt;property name="virtualPrimaryKey" value="ID" /&amp;gt;&lt;br /&gt;      &amp;lt;/virtual-primary-key&amp;gt;&lt;br /&gt;     &amp;lt;/entity&amp;gt;&lt;br /&gt;     &amp;lt;entity name="stat_mb_by_role" alias="MEMBER_PER_ROLE_COUNTRY_AND_CONFERENCE"&amp;gt;&lt;br /&gt;      &amp;lt;virtual-primary-key isRealPrimaryKey="true"&amp;gt;&lt;br /&gt;       &amp;lt;property name="virtualPrimaryKey" value="id" /&amp;gt;&lt;br /&gt;      &amp;lt;/virtual-primary-key&amp;gt;&lt;br /&gt;      &amp;lt;field name="stat_mb_per_ctry_conf_ID" linkToTargetEntity="stat_mb_per_ctry_conf"&lt;br /&gt;       linkToTargetField="id"&amp;gt;&amp;lt;/field&amp;gt;&lt;br /&gt;     &amp;lt;/entity&amp;gt;&lt;br /&gt;    &amp;lt;/enrichment&amp;gt;&lt;br /&gt;   &amp;lt;/business-model&amp;gt;&lt;br /&gt;  &amp;lt;/model&amp;gt;&lt;br /&gt;  &amp;lt;targets&amp;gt;&lt;br /&gt;   &amp;lt;!-- openxava --&amp;gt;&lt;br /&gt;   &amp;lt;target refname="OpenXava" name="OpenXava"&lt;br /&gt;    fileName="mp-template-config-openxava-last-features.xml"&lt;br /&gt;    outputdir-root="../../DEV/output/openxava-springsecurity/conference"&lt;br /&gt;    templatedir-root="../../template/framework/openxava"&amp;gt;&lt;br /&gt;    &amp;lt;property name="add-spring-security" value="true" /&amp;gt;&lt;br /&gt;   &amp;lt;/target&amp;gt;&lt;br /&gt;&lt;br /&gt;   &amp;lt;target refname="CACHE-LIB" fileName="mp-template-config-CACHE-LIB.xml"&lt;br /&gt;    templatedir-root="../../template/framework/cache"&amp;gt;&lt;br /&gt;   &amp;lt;/target&amp;gt;&lt;br /&gt;&lt;br /&gt;   &amp;lt;target refname="springsecurity" name="springsecurity"&lt;br /&gt;    fileName="mp-template-config-spring-security.xml" &lt;br /&gt;                                outputdir-root="../../DEV/output/openxava-springsecurity/conference"&lt;br /&gt;    templatedir-root="../../template/framework/security/spring"&amp;gt;&lt;br /&gt;   &amp;lt;/target&amp;gt;&lt;br /&gt;&lt;br /&gt;   &amp;lt;target refname="JPA2-LIB" fileName="mp-template-config-JPA2-LIB.xml"&lt;br /&gt;    templatedir-root="../../template/framework/jpa"&amp;gt;&lt;br /&gt;   &amp;lt;/target&amp;gt;&lt;br /&gt;&lt;br /&gt;   &amp;lt;target refname="BSLA-LIB" fileName="mp-template-config-bsla-LIB-features.xml"&lt;br /&gt;    templatedir-root="../../template/framework/bsla"&amp;gt;&lt;br /&gt;   &amp;lt;/target&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;/targets&amp;gt;&lt;br /&gt; &amp;lt;/configuration&amp;gt;&lt;br /&gt;&amp;lt;/generator-config&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;The main points are&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;exclude entities starting with user_ (i.e. the security entity used by spring configuration) &lt;/li&gt;&lt;li&gt;add security access on package level&lt;/li&gt;&lt;ul&gt;&lt;li&gt;package admin is accessible by role administrator only&lt;/li&gt;&lt;li&gt;package statistics is accessible by role reviewer only&lt;/li&gt;&lt;li&gt;default package (conference) is accessible by any application_user&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;add spring-security track in the target&lt;/li&gt;&lt;li&gt;add reference in openxava to spring-security&lt;/li&gt;&lt;/ul&gt;The track springsecurity holding the configuration is not yet bundled in minuteproject release 0.8 but will be present for 0.8.1+.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Set up Database&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Implement the views&lt;/b&gt;&lt;br /&gt;Here a very dummy implementation.&lt;br /&gt;&lt;pre class="html" name="code"&gt;create view user_authentication as&lt;br /&gt;select &lt;br /&gt;email as username,&lt;br /&gt;first_name as password,&lt;br /&gt;'1' as active&lt;br /&gt;from &lt;br /&gt;conference_member&lt;br /&gt;;&lt;br /&gt;create view user_authorisation as&lt;br /&gt;select cm.email as username, r.name as role &lt;br /&gt;from conference_member cm, role r, member_role mr&lt;br /&gt;where mr.role_id = r.id&lt;br /&gt;and mr.conference_member_id = cm.id&lt;br /&gt;union&lt;br /&gt;select cm.email as username, concat('ROLE_',r.name) as role &lt;br /&gt;from conference_member cm, role r, member_role mr&lt;br /&gt;where mr.role_id = r.id&lt;br /&gt;and mr.conference_member_id = cm.id&lt;br /&gt;;&lt;br /&gt;&lt;/pre&gt;As you can not there is a little redundancy in the user_authentication view, since sometimes the role administrator is refered sometimes role_administrator. This will be homogenized in next release.&lt;br /&gt;&lt;b&gt;Add some default value&lt;/b&gt;&lt;br /&gt;Here a very dummy implementation.&lt;br /&gt;&lt;pre class="html" name="code"&gt;INSERT INTO country (id, name, iso_name) VALUES (-1, 'France', 'FR');&lt;br /&gt;INSERT INTO address (id, street1, street2, country_id) VALUES(-1, 'rue 1', 'rue 2', -1);&lt;br /&gt;INSERT INTO  conference_member (id, conference_id, first_name, last_name, email, address_id, status )&lt;br /&gt;    VALUES  (-1, -1, 'f', 'a', 'fa@test.com', -1, 'ACTIVE' );&lt;br /&gt;INSERT INTO role (id, name) VALUES (-1, 'ADMINSTRATOR' );  &lt;br /&gt;INSERT INTO role (id, name) VALUES (-2, 'ROLE_APPLICATION_USER' );&lt;br /&gt;INSERT INTO member_role (conference_member_id, role_id) VALUES (-1, -1);  &lt;br /&gt;INSERT INTO member_role (conference_member_id, role_id) VALUES (-1, -2);&lt;br /&gt;&lt;/pre&gt;So when user fa@test.com connects he will get the role Administrator which allows him to access the administrator menu and create a new role called 'REVIEWER'.He can also create a new conference member and associate with the role 'REVIEWER'.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Set up Application&lt;/b&gt;&lt;br /&gt;Download the lazuly-openxava-springsecurity minuteproject configuration from&amp;nbsp;&lt;a href="http://code.google.com/p/minuteproject/downloads/detail?name=mp-template-config-spring-security.xml&amp;amp;can=2&amp;amp;q=#makechanges"&gt;google code minuteproject&lt;/a&gt;.&lt;br /&gt;Copy file into&amp;nbsp;&lt;mp_home&gt;/mywork/config&lt;/mp_home&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Execute&lt;/b&gt;&lt;br /&gt;In &lt;mp_home&gt;/mywork/config: model-generation.cmd mp-config-LAZULY-Openxava-with-spring-security.xml&lt;/mp_home&gt;&lt;br /&gt;The generated code goes to &lt;mp_home&gt;/DEV/output/openxava-springsecurity/conference &lt;/mp_home&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Packaging&lt;/b&gt;&lt;br /&gt;Here the packaging/deployment is a 2 steps exercices (unfortunately):&lt;br /&gt;&lt;ul&gt;&lt;li&gt;there is no more the start-tomcat/stop-tomcat command in OX distribution&lt;/li&gt;&lt;li&gt;spring dependencies are not included&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;Steps&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Check that Openxava 4.3 is available, and OX_HOME is set to Openxava 4.3&lt;/li&gt;&lt;li&gt;from &lt;mp_home&gt;/DEV/output/openxava-springsecurity/conference run build-conference(.cmd/sh). This will trigger the build that is successful but not the deployment due to information before. &lt;/mp_home&gt;&lt;/li&gt;&lt;li&gt;Open the project generated by the build in Openxava workspace&lt;/li&gt;&lt;li&gt;Add Spring security dependencies&lt;/li&gt;&lt;li&gt;Start tomcat server (remark: The Datasource for the application is present in tomcat/config/context.xml)&lt;/li&gt;&lt;li&gt;Deploy&lt;/li&gt;&lt;li&gt;Enjoy&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size: x-large;"&gt;Testing&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Welcome page&lt;/span&gt;&lt;br /&gt;Default URL at context root of the application.&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/-YvnSXIftOow/Tz5H7EnSJOI/AAAAAAAAAGQ/4jdM6VkD7a8/s1600/lazuly-ox-spring-security-welcome.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"&gt;&lt;img border="0" height="75" src="http://3.bp.blogspot.com/-YvnSXIftOow/Tz5H7EnSJOI/AAAAAAAAAGQ/4jdM6VkD7a8/s320/lazuly-ox-spring-security-welcome.png" width="320" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Login page&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-c7psNJcTxz8/Tz5HzdpFPTI/AAAAAAAAAFQ/cAM4CndBCEU/s1600/lazuly-ox-spring-secu-login.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="212" src="http://2.bp.blogspot.com/-c7psNJcTxz8/Tz5HzdpFPTI/AAAAAAAAAFQ/cAM4CndBCEU/s320/lazuly-ox-spring-secu-login.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Any other direct called where the user is not authenticated will be intercepted and routed to this page&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Contextual Menu&lt;/span&gt;&lt;br /&gt;The user have access to the admin and conference part not the statistics.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-xIMmCQlZgFI/Tz5H2HorTqI/AAAAAAAAAFo/qaJeByZU1aQ/s1600/lazuly-ox-spring-security-address-access.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="210" src="http://3.bp.blogspot.com/-xIMmCQlZgFI/Tz5H2HorTqI/AAAAAAAAAFo/qaJeByZU1aQ/s400/lazuly-ox-spring-security-address-access.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The URLs have been modified. When the user tries to access the standard OX style URL he recieves an&lt;br /&gt;access denied (ex: module.jsp)&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-4wzrnl0lfmk/Tz5H4MQpSTI/AAAAAAAAAF4/M0nl2iZG_rs/s1600/lazuly-ox-spring-security-module.jsp-blocked.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="121" src="http://1.bp.blogspot.com/-4wzrnl0lfmk/Tz5H4MQpSTI/AAAAAAAAAF4/M0nl2iZG_rs/s400/lazuly-ox-spring-security-module.jsp-blocked.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Add role reviewer&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-5kMX81Wjiuc/Tz5H1Oeu0kI/AAAAAAAAAFg/HECc9hvfE-g/s1600/lazuly-ox-spring-security-add-reviewer-role.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="295" src="http://2.bp.blogspot.com/-5kMX81Wjiuc/Tz5H1Oeu0kI/AAAAAAAAAFg/HECc9hvfE-g/s400/lazuly-ox-spring-security-add-reviewer-role.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b style="text-align: left;"&gt;Add user&lt;/b&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-R2fcDl_Rzlo/Tz5H0EUGqPI/AAAAAAAAAFY/jPhrtMSxHQE/s1600/lazuly-ox-spring-security-add-conference-member.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="http://2.bp.blogspot.com/-R2fcDl_Rzlo/Tz5H0EUGqPI/AAAAAAAAAFY/jPhrtMSxHQE/s400/lazuly-ox-spring-security-add-conference-member.png" width="222" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="" style="clear: both; text-align: left;"&gt;&lt;b&gt;Affect user with role reviewer and default (application_user)&lt;/b&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-X0ibWY_Owiw/Tz5KjsJL3ZI/AAAAAAAAAGY/6lMwg6Uurc4/s1600/lazuly-ox-spring-security-affecting-reviewer-and-appuser-role.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="http://4.bp.blogspot.com/-X0ibWY_Owiw/Tz5KjsJL3ZI/AAAAAAAAAGY/6lMwg6Uurc4/s400/lazuly-ox-spring-security-affecting-reviewer-and-appuser-role.png" width="298" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="" style="clear: both; text-align: left;"&gt;&lt;span style="font-size: large;"&gt;Logoff&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div class="" style="clear: both; text-align: left;"&gt;(click logoff)&lt;/div&gt;&lt;div class="" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="" style="clear: both; text-align: left;"&gt;&lt;span style="font-size: large;"&gt;Login as Reviewer&lt;/span&gt;&lt;/div&gt;&lt;div class="" style="clear: both; text-align: left;"&gt;On login page enter username=bc@test.com and password=b&lt;/div&gt;&lt;div class="" style="clear: both; text-align: left;"&gt;In the contextual menu you do see the 'admin' package'&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-jDIgo7TornY/Tz5H5Dug6qI/AAAAAAAAAGA/Rv1iuKUez1A/s1600/lazuly-ox-spring-security-reviewer-access.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="225" src="http://1.bp.blogspot.com/-jDIgo7TornY/Tz5H5Dug6qI/AAAAAAAAAGA/Rv1iuKUez1A/s320/lazuly-ox-spring-security-reviewer-access.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="" style="clear: both; text-align: left;"&gt;And you get an access deny when manipulating directly the URL&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-T0nSup6tKJM/Tz5H6MFuhNI/AAAAAAAAAGI/R-HHEsZJnCY/s1600/lazuly-ox-spring-security-reviewer-accessing-countries.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="81" src="http://1.bp.blogspot.com/-T0nSup6tKJM/Tz5H6MFuhNI/AAAAAAAAAGI/R-HHEsZJnCY/s400/lazuly-ox-spring-security-reviewer-accessing-countries.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&amp;nbsp;Now the application is secured.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;Conclusion &lt;/span&gt;&lt;br /&gt;This article showed the configuration and manipulation to integrate spring security with openxava in a non-intrusive manner.&lt;br /&gt;It stressed a new concept 'DB color access spectrum' and how to densify the security information in minuteproject configuration. &lt;br /&gt;DB color access spectrum is a concept which ask only to be extended:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Ad-hoc functions, controllers&lt;/li&gt;&lt;li&gt;Store procedures&lt;/li&gt;&lt;/ul&gt;It is simple to express and analyst friendly.&lt;br /&gt;It is not bound to a technology.&lt;br /&gt;It is a step in easily defining fine grain access, its combination with profile based access and state based access (to do manually... for the moment ;)) could pave the way to &lt;b&gt;intuitive and implicit workflows&lt;/b&gt; instead of heavy BPM solutions.&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8723196641810122152-2650526613831884805?l=minuteproject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://minuteproject.blogspot.com/feeds/2650526613831884805/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://minuteproject.blogspot.com/2012/02/adding-spring-security-to-openxava.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/2650526613831884805'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/2650526613831884805'/><link rel='alternate' type='text/html' href='http://minuteproject.blogspot.com/2012/02/adding-spring-security-to-openxava.html' title='Adding Spring-Security to Openxava'/><author><name>florian</name><uri>http://www.blogger.com/profile/04083442568354390924</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-YvnSXIftOow/Tz5H7EnSJOI/AAAAAAAAAGQ/4jdM6VkD7a8/s72-c/lazuly-ox-spring-security-welcome.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8723196641810122152.post-2915465047795303300</id><published>2011-12-19T06:56:00.000-08:00</published><updated>2012-02-03T15:14:54.471-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='fitnesse'/><category scheme='http://www.blogger.com/atom/ns#' term='liferay'/><category scheme='http://www.blogger.com/atom/ns#' term='querydsl'/><category scheme='http://www.blogger.com/atom/ns#' term='methodology'/><category scheme='http://www.blogger.com/atom/ns#' term='minuteproject'/><category scheme='http://www.blogger.com/atom/ns#' term='jpa2'/><category scheme='http://www.blogger.com/atom/ns#' term='ehcache'/><title type='text'>Productivity by Example: Liferay reverse-engineered</title><content type='html'>In this experiment, minuteproject demonstrates that it is possible to use Reverse-Engineering as a development methodology for Big Projects AND this from bootstrap time to the entire lifecycle of a Project.&lt;br /&gt;&lt;br /&gt;To illustrate this postulat, I take enterprise-size opensource model (Liferay with150+ entities) upon which I apply minuteproject tracks.&lt;br /&gt;It will quickly appear that performing 'bulk reverse-engineering' have strong limitations. Meanwhile by applying conventions deduced from the 'Reverse-Analysis' discipline, it will be possible to overcome them.&lt;br /&gt;The generation will run releasing in couple of seconds (3 to 10) hundreds of artefacts.&lt;br /&gt;Following Minuteproject philosophy, you'll will have to write 0 (Zero) LOC to get a working result and this can be achieved within 5 min-.&lt;br /&gt;Eventually some code will be written on top and the result will be tested.&lt;br /&gt;The technologies discussed will be:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;JPA2 with Hibernate implementation&lt;/li&gt;&lt;li&gt;Querydsl&lt;/li&gt;&lt;li&gt;Ehcache&amp;nbsp;&lt;/li&gt;&lt;li&gt;Fitnesse &lt;/li&gt;&lt;/ul&gt;&lt;div&gt;But other MP tracks can be applied.&lt;/div&gt;&lt;div&gt;The conclusion resumes the productivity benefit at project and enterprise level of embracing MinuteProject productivity philosophy.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;Liferay&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Liferay is an opensource portal, this article only focus on the database model.&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Liferay Model&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;b&gt;&lt;span style="font-size: small;"&gt;Setup&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;The model is install on mysql database.&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Download Liferay Model &lt;a href="https://sourceforge.net/projects/lportal/files/Liferay%20Portal/6.0.6/liferay-portal-sql-6.0.6-20110225.zip/download" target="_blank"&gt;https://sourceforge.net/projects/lportal/files/Liferay%20Portal/6.0.6/liferay-portal-sql-6.0.6-20110225.zip/download&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Unzip&lt;/li&gt;&lt;li&gt;&amp;nbsp;On liferay-portal-sql-6.0.6-20110225\liferay-portal-sql-6.0.6\create&lt;/li&gt;&lt;li&gt;Execute mysql -u root -p xxxx &amp;lt; create-mysql.sql &lt;/li&gt;&lt;/ul&gt;Now you can introspect your model.&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Reverse-Analysis crash course&lt;/b&gt;&lt;/div&gt;&lt;div&gt;At first sight 150+ tables, 0 views.&lt;br /&gt;Some tables start with QUARTZ, those are likely to be shipped with the Quartz scheduling framework, so they should be excluded from the generation. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;At second sight (on mysql installation)&lt;/div&gt;&lt;div&gt;Entity with primary key but no foreign keys.&amp;nbsp;=&amp;gt; No relationships?&lt;/div&gt;&lt;div&gt;Mysql schema primary key are not autoincrement.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If reverse-engineering is performed as-is, then the bulk resulting artefacts in JPA2 will contain no relationships (no @OneToMany, @ManyToOne and @ManyToMany), so the resulting value will be quite poor (no graph navigation, query link to be done manually, no type safe benefit of Querydsl or Metamodel...)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;b&gt;Relation detection convention&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Since the relationships are not formalised in terms of constraint, does it mean that there is none?&lt;/div&gt;&lt;div&gt;In fact, when having a deeper look inside the tables, some fields have name such as USER_ID and there is a strong chance that they are used for a relationship link with the User_ table primary key.&lt;/div&gt;&lt;div&gt;Let's assume it.&lt;/div&gt;&lt;div&gt;Since in minuteproject configuration the user can perform some enrichment and one of this enrichment consists in defining relationship, it is possible to enrich every table containing the field USER_ID by indicating it acts as a foreign key towards USER_ table.&lt;/div&gt;&lt;div&gt;// add snippet&lt;/div&gt;&lt;div&gt;It's fine, but it might be cumbersome since you'll have to do it more than 40 times and only for the 'towards User' relationships. What about the others?&lt;/div&gt;&lt;div&gt;A wiser way is to apply a convention:&lt;br /&gt;What we need is to be able to detect relationships when those match a pattern.The pattern here is that the 'considered' foreign keys are fields ending with 'id' and whose beginning (column name without ending 'id') correspond to an existing table.&lt;br /&gt;But this was not enough since some table ends with '_'.&lt;br /&gt;So the convention has to take care of those exceptions and the match is done against the a map of those entity alias if the match was not successful via direct binding.&lt;br /&gt;The final configuration of the convention is&lt;br /&gt;&lt;br /&gt;&lt;pre class="java" name="code"&gt;&amp;lt;foreign-key-convention type="autodetect-foreign-key-based-on-similarity-and-map" &lt;br /&gt;column-ending="id" column-starting="" column-body="match-entity"&amp;gt;&lt;br /&gt;&amp;lt;property tag="map-entity" name="user_" value="user"/&amp;gt; &lt;br /&gt;&amp;lt;property tag="map-entity" name="group_" value="group"/&amp;gt;&lt;br /&gt;&amp;lt;property tag="map-entity" name="organization_" value="organization"/&amp;gt;&lt;br /&gt;&amp;lt;property tag="map-entity" name="permission_" value="permission"/&amp;gt;&lt;br /&gt;&amp;lt;/foreign-key-convention&amp;gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;&lt;span style="font-size: small;"&gt;With this convention it is now possible to have 'virtual' foreign keys used by the generator to create &lt;/span&gt;&lt;/span&gt;@OneToMany, @ManyToOne and @ManyToMany relationships for JPA2 track.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;&lt;span style="font-size: small;"&gt;&lt;b&gt;Naming convention &lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;&lt;span style="font-size: small;"&gt;The JEE conventions can be different from those retrieved from the Database structure:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;&lt;span style="font-size: small;"&gt; Example: Some column ends with 'id' but in java we might not want that.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;&lt;span style="font-size: small;"&gt;Here the convention for that&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre class="java" name="code"&gt;&amp;lt;column-naming-convention type="apply-strip-column-name-suffix" pattern-to-strip="ID" /&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Collection naming convention&lt;/b&gt;&lt;br /&gt;While reverse-engineering a problem is to give unambiguous names to list elements. Otherwise in java you have a compilation error. The safest way is to compose the name of this collection relationship (@OneToMany) with the name of the field holding the foreign key, and the name of entity having this FK. It get even worse when dealing with a many2many relationship where the intermediary link table as to be associated.&lt;br /&gt;As a result, you can have very long name which is not quite handy.&lt;br /&gt;Fortunately the convention apply-reference-alias-when-no-ambiguity is there for you!&lt;br /&gt;&lt;pre class="java" name="code"&gt;&amp;lt;reference-naming-convention type="apply-referenced-alias-when-no-ambiguity" is-to-plurialize="true" /&amp;gt;&lt;/pre&gt;It checks if while reducing the 'unambiguous' default name to 'just' the associated table (plurialize as option) there is no colision.&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;&lt;span style="font-size: small;"&gt;Remark&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;&lt;span style="font-size: small;"&gt;With conventions bear in mind that they are applied sequentially and so the order is very important!&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-size: small;"&gt;Aliasing&lt;/span&gt;&lt;/b&gt;&lt;span style="font-size: small;"&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;Entity name or column name can be aliased.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;The alias will be used for the Java name but the ORM mapping will&lt;/span&gt; match the alias name to the correct entity name.&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Caching&lt;/b&gt;&lt;br /&gt;To enable caching add a property to the target JPA2&lt;br /&gt;&lt;pre class="xml" name="code"&gt;               &amp;lt;property name="add-cache-implementation" value="ehcache"&amp;gt;&amp;lt;/property&amp;gt;&lt;/pre&gt;It is possible to associate caching to entities by two means:&lt;/div&gt;&lt;div&gt;By enrichment at entity level: Each entity marked as having their content-type="master-data" or ="reference-data" will have an associate cache entry&lt;/div&gt;&lt;pre class="xml" name="code"&gt;&amp;lt;entity name="country" content-type="reference-data"&amp;gt;&amp;lt;/entity&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;By convention: describe a pattern of entity matching the requirement. Example all the entity ending with '_' could be considered as reference data&lt;/div&gt;&lt;pre class="xml" name="code"&gt;&amp;lt;entity-content-type-convention type="apply-content-type-to-entity-ending-with" pattern="_" content-type="reference-data"&amp;gt;&amp;lt;/entity-content-type-convention&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;&lt;span style="font-size: small;"&gt;In this case the entity 'user', 'account', 'classname', 'contact', 'group', 'lock', 'organisation', 'permission', 'release', 'resouce' and 'role' will match the convention and thus have their cache entry in ehcache.xml&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;MinuteProject input&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-size: large;"&gt;Input configuration&lt;/span&gt;&lt;br /&gt;The analysis is resumed in the mp-config_LR.xml serving as input of MinuteProject&lt;/div&gt;&lt;div&gt;&lt;pre class="xml" name="code"&gt;&amp;lt;!DOCTYPE root&amp;gt;&lt;br /&gt;&amp;lt;generator-config&amp;gt;&lt;br /&gt;    &amp;lt;configuration&amp;gt;&lt;br /&gt;        &amp;lt;conventions&amp;gt;&lt;br /&gt;            &amp;lt;target-convention type="enable-updatable-code-feature" /&amp;gt;&lt;br /&gt;        &amp;lt;/conventions&amp;gt;       &lt;br /&gt;        &amp;lt;model name="liferay" version="1.0" package-root="net.sf.mp.demo"&amp;gt;&lt;br /&gt;            &amp;lt;data-model&amp;gt;&lt;br /&gt;                &amp;lt;driver name="mysql" version="5.1.16" groupId="mysql" artifactId="mysql-connector-java"&amp;gt;&amp;lt;/driver&amp;gt;&lt;br /&gt;                &amp;lt;dataSource&amp;gt;&lt;br /&gt;                    &amp;lt;driverClassName&amp;gt;org.gjt.mm.mysql.Driver&amp;lt;/driverClassName&amp;gt;&lt;br /&gt;                    &amp;lt;url&amp;gt;jdbc:mysql://127.0.0.1:3306/lportal&amp;lt;/url&amp;gt;&lt;br /&gt;                    &amp;lt;username&amp;gt;root&amp;lt;/username&amp;gt;&lt;br /&gt;                    &amp;lt;password&amp;gt;mysql&amp;lt;/password&amp;gt;&lt;br /&gt;                &amp;lt;/dataSource&amp;gt;&lt;br /&gt;                &amp;lt;primaryKeyPolicy oneGlobal="true"&amp;gt;&lt;br /&gt;                    &amp;lt;primaryKeyPolicyPattern name="none"&amp;gt;&amp;lt;/primaryKeyPolicyPattern&amp;gt;&lt;br /&gt;                &amp;lt;/primaryKeyPolicy&amp;gt;&lt;br /&gt;            &amp;lt;/data-model&amp;gt;&lt;br /&gt;            &amp;lt;business-model&amp;gt;   &lt;br /&gt;                    &amp;lt;generation-condition&amp;gt;&lt;br /&gt;                    &amp;lt;condition type="exclude" startsWith="QUARTZ"&amp;gt;&amp;lt;/condition&amp;gt;&lt;br /&gt;                    &amp;lt;/generation-condition&amp;gt;&lt;br /&gt;                &amp;lt;business-package default="liferay"&amp;gt;&lt;br /&gt;                    &amp;lt;condition type="package" startsWith="social" result="social"&amp;gt;&amp;lt;/condition&amp;gt;&lt;br /&gt;                    &amp;lt;condition type="package" startsWith="user" result="user"&amp;gt;&amp;lt;/condition&amp;gt;&lt;br /&gt;                    &amp;lt;condition type="package" startsWith="journal" result="journal"&amp;gt;&amp;lt;/condition&amp;gt;               &lt;br /&gt;                &amp;lt;/business-package&amp;gt;&lt;br /&gt;                &amp;lt;enrichment&amp;gt;&lt;br /&gt;                    &amp;lt;conventions&amp;gt;&lt;br /&gt;                        &amp;lt;column-naming-convention type="apply-strip-column-name-suffix" pattern-to-strip="ID" /&amp;gt;&lt;br /&gt;                        &amp;lt;foreign-key-convention type="autodetect-foreign-key-based-on-similarity-and-map"&lt;br /&gt;                            column-ending="id" column-starting="" column-body="match-entity"&amp;gt;&lt;br /&gt;                            &amp;lt;property tag="map-entity" name="user_" value="user"/&amp;gt;&lt;br /&gt;                            &amp;lt;property tag="map-entity" name="group_" value="group"/&amp;gt;&lt;br /&gt;                            &amp;lt;property tag="map-entity" name="organization_" value="organization"/&amp;gt;&lt;br /&gt;                            &amp;lt;property tag="map-entity" name="permission_" value="permission"/&amp;gt;&lt;br /&gt;                        &amp;lt;/foreign-key-convention&amp;gt;&lt;br /&gt;                        &amp;lt;reference-naming-convention type="apply-referenced-alias-when-no-ambiguity" is-to-plurialize="true" /&amp;gt;       &lt;br /&gt;                        &amp;lt;entity-content-type-convention type="apply-content-type-to-entity-ending-with" pattern="_" content-type="reference-data"&amp;gt;&amp;lt;/entity-content-type-convention&amp;gt;&lt;br /&gt;                    &amp;lt;/conventions&amp;gt;&lt;br /&gt;                    &amp;lt;entity name="user_" alias="user"&amp;gt;&amp;lt;/entity&amp;gt;&lt;br /&gt;                    &amp;lt;entity name="role_" alias="role"&amp;gt;&amp;lt;/entity&amp;gt;&lt;br /&gt;                    &amp;lt;entity name="group_" alias="group"&amp;gt;&amp;lt;/entity&amp;gt;&lt;br /&gt;                    &amp;lt;entity name="permission_" alias="permission"&amp;gt;&amp;lt;/entity&amp;gt;&lt;br /&gt;                    &amp;lt;entity name="organization_" alias="organization"&amp;gt;&amp;lt;/entity&amp;gt;&lt;br /&gt;                    &amp;lt;entity name="classname_" alias="classname"&amp;gt;&amp;lt;/entity&amp;gt;&lt;br /&gt;                    &amp;lt;entity name="country" content-type="reference-data"&amp;gt;&amp;lt;/entity&amp;gt;&lt;br /&gt;                &amp;lt;/enrichment&amp;gt;&lt;br /&gt;            &amp;lt;/business-model&amp;gt;&lt;br /&gt;        &amp;lt;/model&amp;gt;&lt;br /&gt;        &amp;lt;targets&amp;gt;&lt;br /&gt;            &amp;lt;target refname="JPA2"&lt;br /&gt;               fileName="mp-template-config-JPA2.xml"&lt;br /&gt;               outputdir-root="../../dev/liferay/output/JPA2"&lt;br /&gt;               templatedir-root="../../template/framework/jpa"&amp;gt;&lt;br /&gt;               &amp;lt;property name="add-querydsl" value="2.1.2"&amp;gt;&amp;lt;/property&amp;gt;&lt;br /&gt;               &amp;lt;property name="add-jpa2-implementation" value="hibernate"&amp;gt;&amp;lt;/property&amp;gt;&lt;br /&gt;               &amp;lt;property name="add-cache-implementation" value="ehcache"&amp;gt;&amp;lt;/property&amp;gt;&lt;br /&gt;               &lt;br /&gt;            &amp;lt;/target&amp;gt;                        &lt;br /&gt;            &amp;lt;target refname="LIB" fileName="mp-template-config-bsla-LIB-features.xml"&lt;br /&gt;                templatedir-root="../../template/framework/bsla"&amp;gt;&lt;br /&gt;            &amp;lt;/target&amp;gt;&lt;br /&gt;    &amp;lt;target refname="CACHE-LIB" &lt;br /&gt;      fileName="mp-template-config-CACHE-LIB.xml" &lt;br /&gt;      templatedir-root="../../template/framework/cache"&amp;gt;&lt;br /&gt;    &amp;lt;/target&amp;gt;            &lt;br /&gt;        &amp;lt;/targets&amp;gt;&lt;br /&gt;    &amp;lt;/configuration&amp;gt;&lt;br /&gt;&amp;lt;/generator-config&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Generation&lt;/span&gt;&lt;br /&gt;Adapt the above config with the liferay database connection credentials.&lt;br /&gt;You need version 0.7+ of &lt;a href="https://sourceforge.net/projects/minuteproject/files/"&gt;minuteproject&lt;/a&gt; (and check that everything is fine by running the &lt;a href="http://minuteproject.wikispaces.com/Demos"&gt;demos&lt;/a&gt;) &lt;br /&gt;To generate place the following file mp-config_LR.xml into /mywork/config&lt;br /&gt;Execute &lt;b&gt;model-generation.(sh/cmd) mp-config_LR.xml&lt;/b&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;MinuteProject output&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-size: large;"&gt;Generated artefacts&lt;/span&gt;&lt;br /&gt;&lt;b&gt;Entities&lt;/b&gt;&lt;br /&gt;140+ entities have been created&lt;br /&gt;12 Embeddable Id when composite primary have been found&lt;br /&gt;&lt;b&gt;Relationships &lt;/b&gt;&lt;br /&gt;+- 300 OneToMany&lt;br /&gt;+- 300 ManyToOne&lt;br /&gt;+- 20 ManyToMany&lt;br /&gt;&lt;b&gt;Configuration&lt;/b&gt;&lt;br /&gt;Entity Associate MetaModel for typesafe query&lt;b&gt; &lt;/b&gt;&lt;br /&gt;Maven pom.xml with querydsl integration&lt;br /&gt;persistence.xml for test (local connection pool) and for release (jndi connection pool).&lt;br /&gt;ehcache.xml&lt;br /&gt;&lt;br /&gt;&lt;div style="color: red;"&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;And All That in 10s less!&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;(local instance of mysql)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If you want to see what the resulting code looks like you can download on&amp;nbsp;&lt;a href="http://code.google.com/p/minuteproject/downloads/detail?name=jooq-liferay-mp-0.8.zip&amp;amp;can=2&amp;amp;q="&gt;googlecode&lt;/a&gt;&amp;nbsp;(version for minuteproject 0.8).&lt;br /&gt;If you want to see what the Liferay datamodel looks like with relationships check&amp;nbsp;&lt;a href="http://code.google.com/p/minuteproject/downloads/detail?name=liferay-with-fk.svg&amp;amp;can=2&amp;amp;q="&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Test&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;u&gt;But does it really work?&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;The sources are generated in &lt;mp_home&gt;/dev/liferay/output/JPA2 &lt;u&gt;&lt;/u&gt;&lt;/mp_home&gt;&lt;br /&gt;Writing a simple unit test in src/test/java which illustrates:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;that you can write business added value&lt;/li&gt;&lt;li&gt;that querydsl for typesafe as an alternative to metamodel (MetaModel entities are also generated) is integrated&lt;/li&gt;&lt;li&gt;that ORM, ehcache configuration works&lt;/li&gt;&lt;/ul&gt;&lt;pre class="java" name="code"&gt;package my.liferay.test;&lt;br /&gt;&lt;br /&gt;import java.util.List;&lt;br /&gt;&lt;br /&gt;import javax.persistence.*;&lt;br /&gt;&lt;br /&gt;import com.mysema.query.jpa.impl.JPAQuery;&lt;br /&gt;&lt;br /&gt;import junit.framework.TestCase;&lt;br /&gt;import net.sf.mp.demo.liferay.domain.liferay.Country;&lt;br /&gt;import net.sf.mp.demo.liferay.domain.liferay.QCountry;&lt;br /&gt;&lt;br /&gt;public class LiferayJPA2Test extends TestCase{&lt;br /&gt;   &lt;br /&gt;    public void testCountry() {&lt;br /&gt;        // Initializes the Entity manager&lt;br /&gt;        EntityManagerFactory emf = Persistence.createEntityManagerFactory("liferay");&lt;br /&gt;        EntityManager em = emf.createEntityManager();&lt;br /&gt;        EntityTransaction tx = em.getTransaction();&lt;br /&gt;&lt;br /&gt;        //use Query dsl for type safe query&lt;br /&gt;        JPAQuery query = new JPAQuery(em);&lt;br /&gt;        QCountry qcountry = QCountry.country;&lt;br /&gt;        List&lt;country&gt; l = query.from(qcountry)&lt;br /&gt;           .where(qcountry.countryid.lt(0))&lt;br /&gt;           .list(qcountry);&lt;br /&gt;        //remove the countries&lt;br /&gt;        for (Country country:l) {&lt;br /&gt;         em.remove(country);&lt;br /&gt;        }&lt;br /&gt;        // create a country&lt;br /&gt;        Country c = new Country();&lt;br /&gt;        // no primary policy key given so associate one manually &lt;br /&gt;        c.setCountryid(new Long(-100));&lt;br /&gt;        c.setName("NEW-country");&lt;br /&gt;        c.setA2("A2");&lt;br /&gt;        c.setA3("A3");&lt;br /&gt;        c.setActive(new Short("1"));&lt;br /&gt;        c.setNumber("5");&lt;br /&gt;&lt;br /&gt;        tx.begin();&lt;br /&gt;        em.persist(c);&lt;br /&gt;        tx.commit();&lt;br /&gt;&lt;br /&gt;        em.close();&lt;br /&gt;        emf.close();   &lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/country&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Running with maven&lt;/b&gt;&lt;br /&gt;Execute mvn package&lt;br /&gt;This will compile and test the code.&lt;br /&gt;In the build, querydsl classes will be generated and compiled&lt;br /&gt;In the test, at run time, ORM and ehcache configuration will be loaded.&lt;br /&gt;&lt;br /&gt;The sql statement issue by Hibernate at the end of the test is&amp;nbsp; &lt;br /&gt;&lt;pre class="java" name="code"&gt;Hibernate:&lt;br /&gt;    insert&lt;br /&gt;    into&lt;br /&gt;        country&lt;br /&gt;        (a2, a3, active_, idd_, name, number_, countryId)&lt;br /&gt;    values&lt;br /&gt;        (?, ?, ?, ?, ?, ?, ?)&lt;br /&gt;&lt;/pre&gt;So yes, it works!&lt;br /&gt;And package liferayBackEnd-1.0-SNAPSHOT.jar is created.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;u&gt;But what happens if there is a compile time or runtime issue with the generated code?&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;Do not worry the generated code is updatable which means that you can patch the code but your modification will be kept over successive generations. More information at &lt;a href="http://minuteproject.wikispaces.com/Updatable_Generated_Code"&gt;http://minuteproject.wikispaces.com/Updatable_Generated_Code&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;Extend&lt;/span&gt;&lt;br /&gt;Here the reverse-engineering target &lt;u&gt;&lt;b&gt;just&lt;/b&gt;&lt;/u&gt; one type of target JPA2 track.&lt;br /&gt;&lt;span style="font-size: large;"&gt;Extend with other MinuteProject tracks &lt;/span&gt;&lt;br /&gt;Example:&lt;br /&gt;FitNessize you development: Adding the following snippet into the 'targets' node of the main configuration will generate an entire Fitnesse wiki ready to use for your acceptance testing.&lt;br /&gt;&lt;pre class="xml" name="code"&gt;   &amp;lt;target refname="FitNesse" &lt;br /&gt;      name="default" &lt;br /&gt;      fileName="mp-template-config-fitnesse.xml" &lt;br /&gt;      outputdir-root="../../dev/liferay/output/FITNESSE"&lt;br /&gt;      templatedir-root="../../template/framework/fitnesse"&amp;gt;&lt;br /&gt;   &amp;lt;/target&amp;gt;&lt;br /&gt;&lt;/pre&gt;For more information see &lt;a href="http://minuteproject.blogspot.com/2011/10/fitnessize-your-jee-dev-with.html"&gt;this article&lt;/a&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Extend you model&lt;/span&gt;&lt;br /&gt;Enrich you model with:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;views&lt;/li&gt;&lt;li&gt;store procedure&lt;/li&gt;&lt;li&gt; constraints&lt;/li&gt;&lt;/ul&gt;Minuteproject will generate relevant artefacts for them. &lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;Conclusions&lt;/span&gt;&lt;br /&gt;&lt;div&gt;This article shows how to set reverse-engineering approach as a fast development methodology.&lt;br /&gt;It is far less intrusive and restricted than Domain Driven Development and much faster.&lt;br /&gt;This article also insists on how to apply your &lt;b&gt;own&lt;/b&gt; conventions via 'declarative conventions'.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Minuteproject&amp;nbsp;unleashes your productivity!&lt;/b&gt;&lt;br /&gt;Things and tedious tasks that where bound to stay for the lifetime of your project can be removed.&lt;br /&gt;At this point it takes more time for a DBA to write and execute an alter statement than to have full backend synchronisation!&lt;br /&gt;&lt;u&gt;Now you can move agile on your backend development. &lt;/u&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;u&gt;Conclusion for the LifeRay Dev team:&lt;/u&gt;&lt;/div&gt;&lt;div&gt;Altering your backend might be quite long if you want to go to JPA2 track described above. Meanwhile you can use MinuteProject without any intrusivity on other tracks.&lt;br /&gt;MinuteProject FitNesse fixture generated for Liferay and this really help increasing QA!&lt;/div&gt;&lt;div&gt;Try other MinuteProject tracks: for example any DB query can be RESTified (fully REST app generated) within seconds...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;More information&lt;/span&gt;&lt;br /&gt;More information about Minuteproject 4 JPA2 track can be found &lt;a href="http://minuteproject.wikispaces.com/JPA2"&gt;here&lt;/a&gt;.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8723196641810122152-2915465047795303300?l=minuteproject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://minuteproject.blogspot.com/feeds/2915465047795303300/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://minuteproject.blogspot.com/2011/12/productivity-by-example-liferay-reverse.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/2915465047795303300'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/2915465047795303300'/><link rel='alternate' type='text/html' href='http://minuteproject.blogspot.com/2011/12/productivity-by-example-liferay-reverse.html' title='Productivity by Example: Liferay reverse-engineered'/><author><name>florian</name><uri>http://www.blogger.com/profile/04083442568354390924</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8723196641810122152.post-705883891423286727</id><published>2011-12-15T05:54:00.000-08:00</published><updated>2011-12-16T00:23:27.362-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='openxava'/><category scheme='http://www.blogger.com/atom/ns#' term='minuteproject'/><category scheme='http://www.blogger.com/atom/ns#' term='jpa2'/><category scheme='http://www.blogger.com/atom/ns#' term='ehcache'/><title type='text'>Adding Ehcache to Openxava application</title><content type='html'>&lt;span style="font-size: x-large;"&gt;Introduction&lt;/span&gt;&lt;br /&gt;This article shows how to quickly enable Ehcache on Openxava applications and thus improving performance.&lt;br /&gt;When viewing an entity and its graph, relationships are loaded. Adding a second-level cache fasten the retrieval of associated elements, since already loaded elements are retrieved from cache and not database.&lt;br /&gt;Eventually this page explains how minuteproject treats this aspect with keeping its promise: write nothing.&lt;br /&gt;As an example, we will take the Lazuly minuteproject showcase. &lt;br /&gt;&lt;span style="font-size: x-large;"&gt;Openxava-Ehcache integration&lt;/span&gt;&lt;br /&gt;In Openxava, you describe your model in the manner of Java annotated POJO.The annotations come from the standard JPA2 ORM and Openxava specific ones.&lt;br /&gt;But nothing prevents you to add others. This is what is done to add caching. There are also couple of configurations to undertake to enable caching.&lt;br /&gt;&lt;span style="font-size: large;"&gt;List of actions&lt;/span&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Add ehcache.xml config file at the root of your sources&lt;/li&gt;&lt;li&gt;Modify persistence.xml to include second level cache&lt;/li&gt;&lt;li&gt;Add caching annotation (alongside JPA2)&lt;/li&gt;&lt;/ol&gt;&lt;u&gt;Remark:&lt;/u&gt;&lt;br /&gt;Openxava comes with the ehcache.jar so there is no need to add a dependency.&lt;br /&gt;&lt;ol&gt;&lt;/ol&gt;&lt;span style="font-size: large;"&gt;Detailed actions&lt;/span&gt;&lt;br /&gt;&lt;b&gt;Add ehcache.xml&lt;/b&gt;&lt;br /&gt;In &lt;ox-project&gt;/persistence place ehcache.xml file&lt;/ox-project&gt;&lt;br /&gt;&lt;pre class="xml" name="code"&gt;&amp;lt;ehcache&amp;gt;&lt;br /&gt;    &amp;lt;defaultCache&lt;br /&gt;            maxElementsInMemory="1000"&lt;br /&gt;            eternal="false"&lt;br /&gt;            timeToIdleSeconds="300"&lt;br /&gt;            timeToLiveSeconds="300"&lt;br /&gt;            overflowToDisk="false"&lt;br /&gt;            diskPersistent="false"&lt;br /&gt;            diskExpiryThreadIntervalSeconds="300"&lt;br /&gt;            memoryStoreEvictionPolicy="LRU"&lt;br /&gt;            /&amp;gt;&lt;br /&gt;   &amp;lt;cache&lt;br /&gt;    name="your.domain.object"&lt;br /&gt;    maxElementsInMemory="5000"&lt;br /&gt;    eternal="false"&lt;br /&gt;    timeToIdleSeconds="300"&lt;br /&gt;    timeToLiveSeconds="600"&lt;br /&gt;    overflowToDisk="false"&lt;br /&gt;   /&amp;gt;&lt;br /&gt;&amp;lt;/ehcache&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;Modify persistence.xml&lt;/b&gt;&lt;br /&gt;Persistence.xml file contains information related to the persitence unit such as connection pool info, class or configuration to load. 'persistence.xml' is located in &lt;ox-project&gt;/persistence/META-INF&lt;/ox-project&gt;&lt;br /&gt;We will append properties for L2 cache. &lt;br /&gt;&lt;pre class="xml" name="code"&gt;        &amp;lt;properties&amp;gt;&lt;br /&gt;            &amp;lt;property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/&amp;gt;&lt;br /&gt;            &amp;lt;property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.SingletonEhCacheProvider" /&amp;gt;&lt;br /&gt;            &amp;lt;property name="net.sf.ehcache.configurationResourceName" value="/ehcache.xml" /&amp;gt;&lt;br /&gt;            &amp;lt;property name="hibernate.cache.use_query_cache" value="true" /&amp;gt;&lt;br /&gt;            &amp;lt;property name="hibernate.cache.use_second_level_cache" value="true" /&amp;gt;&lt;br /&gt;            &amp;lt;property name="hibernate.generate_statistics" value="true" /&amp;gt;   &lt;br /&gt;&lt;br /&gt;        &amp;lt;/properties&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;Add cache annotation&lt;/b&gt;&lt;br /&gt;Here the hibernate annotation is used instead of the standard one (Cacheable in fact seems not to work)&lt;br /&gt;Place Cache annotation at class level of your domain object.&lt;br /&gt;&lt;pre class="java" name="code"&gt;@org.hibernate.annotations.Cache(usage = org.hibernate.annotations.CacheConcurrencyStrategy.READ_WRITE)&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-size: x-large;"&gt;Example&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Lazuly application &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;Lazuly is a sample database holding conference information used for MinuteProject showcase purpose.&lt;br /&gt;Minuteproject generates a comprehensive set of artefacts to speedup the release of OX application.&lt;br /&gt;Further information can be found in &lt;a href="http://minuteproject.blogspot.com/2011/06/minuteproject-4-openxava-lazuly.html"&gt;Minuteproject 4 Openxava Lazuly showcase&lt;/a&gt;. &lt;br /&gt;On this part we focus on the artefacts generated for the caching specific.&lt;br /&gt;Minuteproject for the generation base itself on a configuration file, where we define the datamodel to reverse engineer. In this configuration there is an enrichement part where you can add information.&lt;br /&gt;One of this information deals with the type of content is held in an entity. There are 4 possibilities (reference-data, master-data, pseudo-static-data, live-business-data)&lt;br /&gt;If you enrich your entity with the content-type="master-data" or "reference-data" MinuteProject 4 Openxava will generate associated caching.&lt;br /&gt;This is done here for the entity Country.&lt;br /&gt;&lt;pre class="xml" name="code"&gt;     &amp;lt;entity name="COUNTRY" content-type="reference-data"&amp;gt;&lt;/pre&gt;&lt;u&gt;Here are the cache related artefacts &lt;/u&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;ehcache.xml&lt;/b&gt;&lt;br /&gt;&lt;pre class="xml" name="code"&gt;&amp;lt;ehcache&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;!--&lt;br /&gt;    Sets the path to the directory where cache files are created.&lt;br /&gt;&lt;br /&gt;    If the path is a Java System Property it is replaced by its value in the&lt;br /&gt;    running VM.&lt;br /&gt;&lt;br /&gt;    The following properties are translated:&lt;br /&gt;    * user.home - User's home directory&lt;br /&gt;    * user.dir - User's current working directory&lt;br /&gt;    * java.io.tmpdir - Default temp file path&lt;br /&gt;&lt;br /&gt;    Subdirectories can be specified below the property e.g. java.io.tmpdir/one&lt;br /&gt;    --&amp;gt;&lt;br /&gt;&amp;lt;!--MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @ehcache-main-config-conference@--&amp;gt;&lt;br /&gt;    &amp;lt;diskStore path="java.io.tmpdir"/&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;!--&lt;br /&gt;    Mandatory Default Cache configuration. These settings will be applied to caches&lt;br /&gt;    created programmtically using CacheManager.add(String cacheName)&lt;br /&gt;    --&amp;gt;&lt;br /&gt;    &amp;lt;defaultCache&lt;br /&gt;            maxElementsInMemory="1000"&lt;br /&gt;            eternal="false"&lt;br /&gt;            timeToIdleSeconds="300"&lt;br /&gt;            timeToLiveSeconds="300"&lt;br /&gt;            overflowToDisk="false"&lt;br /&gt;            diskPersistent="false"&lt;br /&gt;            diskExpiryThreadIntervalSeconds="300"&lt;br /&gt;            memoryStoreEvictionPolicy="LRU"&lt;br /&gt;            /&amp;gt;&lt;br /&gt;&amp;lt;!-- The unnamed query cache --&amp;gt;&lt;br /&gt;   &amp;lt;cache&lt;br /&gt;    name="org.hibernate.cache.StandardQueryCache"&lt;br /&gt;    maxElementsInMemory="1000"&lt;br /&gt;    eternal="false"&lt;br /&gt;    timeToLiveSeconds="300"&lt;br /&gt;    overflowToDisk="false"&lt;br /&gt;   /&amp;gt;&lt;br /&gt;&amp;lt;!--MP-MANAGED-UPDATABLE-ENDING--&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!--MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @cache-entity-country-conference@--&amp;gt;&lt;br /&gt;   &amp;lt;cache&lt;br /&gt;    name="net.sf.mp.demo.conference.domain.admin.Country"&lt;br /&gt;    maxElementsInMemory="5000"&lt;br /&gt;    eternal="false"&lt;br /&gt;    timeToIdleSeconds="300"&lt;br /&gt;    timeToLiveSeconds="600"&lt;br /&gt;    overflowToDisk="false"&lt;br /&gt;   /&amp;gt;&lt;br /&gt;&amp;lt;!--MP-MANAGED-UPDATABLE-ENDING--&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!--MP-MANAGED-ADDED-AREA-BEGINNING @custom-cache-definition@--&amp;gt;&lt;br /&gt;&amp;lt;!--MP-MANAGED-ADDED-AREA-ENDING @custom-cache-definition@--&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/ehcache&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;Persistence.xml&lt;/b&gt;&lt;br /&gt;&lt;pre class="xml" name="code"&gt;&amp;lt;persistence xmlns="http://java.sun.com/xml/ns/persistence"&lt;br /&gt;             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"&lt;br /&gt;             version="1.0"&amp;gt;&lt;br /&gt;             &lt;br /&gt;    &amp;lt;!-- Tomcat + Hypersonic --&amp;gt;&lt;br /&gt;    &amp;lt;persistence-unit name="default"&amp;gt;&lt;br /&gt;     &amp;lt;non-jta-data-source&amp;gt;java:comp/env/jdbc/conferenceDS&amp;lt;/non-jta-data-source&amp;gt;&lt;br /&gt;     &amp;lt;class&amp;gt;org.openxava.session.GalleryImage&amp;lt;/class&amp;gt;&lt;br /&gt;        &amp;lt;properties&amp;gt;&lt;br /&gt;            &amp;lt;property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/&amp;gt;&lt;br /&gt;            &amp;lt;property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.SingletonEhCacheProvider" /&amp;gt;&lt;br /&gt;            &amp;lt;property name="net.sf.ehcache.configurationResourceName" value="/ehcache.xml" /&amp;gt;&lt;br /&gt;            &amp;lt;property name="hibernate.cache.use_query_cache" value="true" /&amp;gt;&lt;br /&gt;            &amp;lt;property name="hibernate.cache.use_second_level_cache" value="true" /&amp;gt;&lt;br /&gt;            &amp;lt;property name="hibernate.generate_statistics" value="true" /&amp;gt;   &lt;br /&gt;&amp;lt;!--MP-MANAGED-ADDED-AREA-BEGINNING @properties@--&amp;gt;&lt;br /&gt;&amp;lt;!--MP-MANAGED-ADDED-AREA-ENDING @properties@--&amp;gt;&lt;br /&gt;        &amp;lt;/properties&amp;gt;&lt;br /&gt;&amp;lt;!--MP-MANAGED-ADDED-AREA-BEGINNING @persistence-unit@--&amp;gt;&lt;br /&gt;&amp;lt;!--MP-MANAGED-ADDED-AREA-ENDING @persistence-unit@--&amp;gt;&lt;br /&gt;    &amp;lt;/persistence-unit&amp;gt;       &lt;br /&gt;&lt;br /&gt;&amp;lt;!--MP-MANAGED-ADDED-AREA-BEGINNING @persistence@--&amp;gt;&lt;br /&gt;&amp;lt;!--MP-MANAGED-ADDED-AREA-ENDING @persistence@--&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/persistence&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;Class annotation &lt;/b&gt;&lt;br /&gt;&lt;pre class="java" name="code"&gt;@org.hibernate.annotations.Cache(usage = org.hibernate.annotations.CacheConcurrencyStrategy.READ_WRITE)&lt;br /&gt;//MP-MANAGED-ADDED-AREA-BEGINNING @class-annotation@&lt;br /&gt;//MP-MANAGED-ADDED-AREA-ENDING @class-annotation@&lt;br /&gt;public class Country {&lt;br /&gt;&lt;br /&gt;    @Hidden @Id @Column(name="id" )&lt;br /&gt;    @GeneratedValue(strategy = GenerationType.AUTO)&lt;br /&gt;    private Integer id; &lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;u&gt;&lt;b&gt;Generated code remark&lt;/b&gt;&lt;/u&gt; &lt;br /&gt;The generated code has markers inside file extension comment.&lt;br /&gt;Within MP-MANAGED-ADDED-AREA-BEGINNING and&amp;nbsp; MP-MANAGED-ADDED-AREA-ENDING you can place customized code&lt;br /&gt;Within MP-MANAGED-UPDATABLE-BEGINNING-DISABLE and&amp;nbsp; MP-MANAGED-UPDATABLE-ENDING you can alter the code. To keep your modifications please change MP-MANAGED-UPDATABLE-BEGINNING-DISABLE into MP-MANAGED-UPDATABLE-BEGINNING-ENABLE.&lt;br /&gt;Updatable code prevent you to lose your customisation over consecutive generations. &lt;br /&gt;For more information on updatable code see &lt;a href="http://minuteproject.wikispaces.com/Updatable_Generated_Code"&gt;Minuteproject updatable code&lt;/a&gt;. &lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;span style="font-size: x-large;"&gt;Generation&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Place the following file mp-config-LAZULY-OPENXAVA.xml in &lt;mp_home&gt;/mywork/config&lt;/mp_home&gt;&lt;/li&gt;&lt;li&gt;on a prompt execute mp-model-generation(.sh/cmd) mp-config-LAZULY-OPENXAVA.xml&amp;nbsp;&lt;/li&gt;&lt;li&gt;the resulting artefacts in &lt;mp_home&gt;/DEV/output/openxava/conference&amp;nbsp; &lt;/mp_home&gt;&lt;/li&gt;&lt;/ul&gt;To generate use the updated version of mp-config-LAZULY-OPENXAVA.xml&lt;br /&gt;&lt;pre class="xml" name="code"&gt;&amp;lt;!DOCTYPE root&amp;gt;&lt;br /&gt;&amp;lt;generator-config&amp;gt;&lt;br /&gt; &amp;lt;configuration&amp;gt;&lt;br /&gt;  &amp;lt;conventions&amp;gt;&lt;br /&gt;   &amp;lt;target-convention type="enable-updatable-code-feature" /&amp;gt;&lt;br /&gt;  &amp;lt;/conventions&amp;gt;  &lt;br /&gt;  &amp;lt;model name="conference" version="1.0" package-root="net.sf.mp.demo"&amp;gt;&lt;br /&gt;   &amp;lt;data-model&amp;gt;&lt;br /&gt;    &amp;lt;driver name="mysql" version="5.1.16" groupId="mysql" artifactId="mysql-connector-java"&amp;gt;&amp;lt;/driver&amp;gt;&lt;br /&gt;    &amp;lt;dataSource&amp;gt;&lt;br /&gt;     &amp;lt;driverClassName&amp;gt;org.gjt.mm.mysql.Driver&amp;lt;/driverClassName&amp;gt;&lt;br /&gt;     &amp;lt;url&amp;gt;jdbc:mysql://127.0.0.1:3306/conference&amp;lt;/url&amp;gt;&lt;br /&gt;     &amp;lt;username&amp;gt;root&amp;lt;/username&amp;gt;&lt;br /&gt;     &amp;lt;password&amp;gt;mysql&amp;lt;/password&amp;gt;&lt;br /&gt;    &amp;lt;/dataSource&amp;gt;&lt;br /&gt;    &amp;lt;!--&lt;br /&gt;     for Oracle and DB2 please set the schema &amp;lt;schema&amp;gt; &amp;lt;/schema&amp;gt;&lt;br /&gt;    --&amp;gt;&lt;br /&gt;    &amp;lt;primaryKeyPolicy oneGlobal="true"&amp;gt;&lt;br /&gt;     &amp;lt;primaryKeyPolicyPattern name="autoincrementPattern"&amp;gt;&amp;lt;/primaryKeyPolicyPattern&amp;gt;&lt;br /&gt;    &amp;lt;/primaryKeyPolicy&amp;gt;&lt;br /&gt;   &amp;lt;/data-model&amp;gt;&lt;br /&gt;   &amp;lt;business-model&amp;gt;&lt;br /&gt;    &amp;lt;!--&lt;br /&gt;     &amp;lt;generation-condition&amp;gt; &amp;lt;condition type="exclude"&lt;br /&gt;     startsWith="DUAL"&amp;gt;&amp;lt;/condition&amp;gt; &amp;lt;/generation-condition&amp;gt;&lt;br /&gt;    --&amp;gt;&lt;br /&gt;    &amp;lt;business-package default="conference"&amp;gt;&lt;br /&gt;        &amp;lt;condition type="package" startsWith="STAT" result="statistics"&amp;gt;&amp;lt;/condition&amp;gt;&lt;br /&gt;        &amp;lt;condition type="package" startsWith="COUNTRY" result="admin"&amp;gt;&amp;lt;/condition&amp;gt;&lt;br /&gt;        &amp;lt;condition type="package" startsWith="ROLE" result="admin"&amp;gt;&amp;lt;/condition&amp;gt;    &lt;br /&gt;    &amp;lt;/business-package&amp;gt;&lt;br /&gt;    &amp;lt;enrichment&amp;gt;&lt;br /&gt;     &amp;lt;conventions&amp;gt;&lt;br /&gt;      &amp;lt;column-naming-convention type="apply-strip-column-name-suffix"&lt;br /&gt;       pattern-to-strip="_ID" /&amp;gt;&lt;br /&gt;      &amp;lt;reference-naming-convention&lt;br /&gt;       type="apply-referenced-alias-when-no-ambiguity" is-to-plurialize="true" /&amp;gt;&lt;br /&gt;     &amp;lt;/conventions&amp;gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;entity name="COUNTRY" content-type="reference-data"&amp;gt;&lt;br /&gt;      &amp;lt;semantic-reference&amp;gt;&lt;br /&gt;       &amp;lt;sql-path path="NAME" /&amp;gt;&lt;br /&gt;      &amp;lt;/semantic-reference&amp;gt;&lt;br /&gt;     &amp;lt;/entity&amp;gt;&lt;br /&gt;     &amp;lt;entity name="CONFERENCE_MEMBER"&amp;gt;&lt;br /&gt;      &amp;lt;semantic-reference&amp;gt;&lt;br /&gt;       &amp;lt;sql-path path="FIRST_NAME" /&amp;gt;&lt;br /&gt;       &amp;lt;sql-path path="LAST_NAME" /&amp;gt;&lt;br /&gt;      &amp;lt;/semantic-reference&amp;gt;&lt;br /&gt;      &amp;lt;field name="STATUS"&amp;gt;&lt;br /&gt;       &amp;lt;property tag="checkconstraint" alias="conference_member_status"&amp;gt;&lt;br /&gt;        &amp;lt;property name="PENDING" value="PENDING" /&amp;gt;&lt;br /&gt;        &amp;lt;property name="ACTIVE" value="ACTIVE" /&amp;gt;&lt;br /&gt;       &amp;lt;/property&amp;gt;&lt;br /&gt;      &amp;lt;/field&amp;gt;&lt;br /&gt;      &amp;lt;field name="EMAIL"&amp;gt;&lt;br /&gt;       &amp;lt;stereotype stereotype="EMAIL" /&amp;gt;&lt;br /&gt;      &amp;lt;/field&amp;gt;&lt;br /&gt;     &amp;lt;/entity&amp;gt;&lt;br /&gt;     &amp;lt;entity name="SPEAKER"&amp;gt;&lt;br /&gt;      &amp;lt;field name="BIO"&amp;gt;&lt;br /&gt;       &amp;lt;stereotype stereotype="HTML_TEXT" /&amp;gt;&lt;br /&gt;      &amp;lt;/field&amp;gt;&lt;br /&gt;      &amp;lt;field name="PHOTO"&amp;gt;&lt;br /&gt;       &amp;lt;stereotype stereotype="PHOTO" /&amp;gt;&lt;br /&gt;      &amp;lt;/field&amp;gt;&lt;br /&gt;      &amp;lt;field name="WEB_SITE_URL"&amp;gt;&lt;br /&gt;       &amp;lt;stereotype stereotype="WEBURL" /&amp;gt;&lt;br /&gt;      &amp;lt;/field&amp;gt;&lt;br /&gt;     &amp;lt;/entity&amp;gt;&lt;br /&gt;     &amp;lt;entity name="PRESENTATION"&amp;gt;&lt;br /&gt;      &amp;lt;field name="STATUS"&amp;gt;&lt;br /&gt;       &amp;lt;property tag="checkconstraint" alias="presentation_status"&amp;gt;&lt;br /&gt;        &amp;lt;property name="PROPOSAL" value="PROPOSAL" /&amp;gt;&lt;br /&gt;        &amp;lt;property name="ACTIVE" value="ACTIVE" /&amp;gt;&lt;br /&gt;       &amp;lt;/property&amp;gt;&lt;br /&gt;      &amp;lt;/field&amp;gt;&lt;br /&gt;     &amp;lt;/entity&amp;gt;&lt;br /&gt;     &amp;lt;entity name="SPONSOR"&amp;gt;&lt;br /&gt;      &amp;lt;field name="STATUS"&amp;gt;&lt;br /&gt;       &amp;lt;property tag="checkconstraint" alias="sponsor_status"&amp;gt;&lt;br /&gt;        &amp;lt;property name="PENDING" value="PENDING" /&amp;gt;&lt;br /&gt;        &amp;lt;property name="ACTIVE" value="ACTIVE" /&amp;gt;&lt;br /&gt;       &amp;lt;/property&amp;gt;&lt;br /&gt;      &amp;lt;/field&amp;gt;&lt;br /&gt;      &amp;lt;field name="PRIVILEGE_TYPE"&amp;gt;&lt;br /&gt;       &amp;lt;property tag="checkconstraint" alias="sponsor_privilege"&amp;gt;&lt;br /&gt;        &amp;lt;property name="GOLDEN" value="Golden" /&amp;gt;&lt;br /&gt;        &amp;lt;property name="SILVER" value="Silver" /&amp;gt;&lt;br /&gt;        &amp;lt;property name="BRONZE" value="Bronze" /&amp;gt;&lt;br /&gt;       &amp;lt;/property&amp;gt;&lt;br /&gt;      &amp;lt;/field&amp;gt;&lt;br /&gt;     &amp;lt;/entity&amp;gt;&lt;br /&gt;     &amp;lt;!-- views --&amp;gt;&lt;br /&gt;     &amp;lt;entity name="stat_mb_per_ctry_conf" alias="MEMBER_PER_COUNTRY_AND_CONFERENCE"&amp;gt;&lt;br /&gt;      &amp;lt;virtual-primary-key isRealPrimaryKey="true"&amp;gt;&lt;br /&gt;       &amp;lt;property name="virtualPrimaryKey" value="ID" /&amp;gt;&lt;br /&gt;      &amp;lt;/virtual-primary-key&amp;gt;&lt;br /&gt;     &amp;lt;/entity&amp;gt;&lt;br /&gt;     &amp;lt;entity name="stat_mb_by_role" alias="MEMBER_PER_ROLE_COUNTRY_AND_CONFERENCE"&amp;gt;&lt;br /&gt;      &amp;lt;virtual-primary-key isRealPrimaryKey="true"&amp;gt;&lt;br /&gt;       &amp;lt;property name="virtualPrimaryKey" value="id" /&amp;gt;&lt;br /&gt;      &amp;lt;/virtual-primary-key&amp;gt;&lt;br /&gt;      &amp;lt;field name="stat_mb_per_ctry_conf_ID" linkToTargetEntity="stat_mb_per_ctry_conf"&lt;br /&gt;       linkToTargetField="id"&amp;gt;&amp;lt;/field&amp;gt;&lt;br /&gt;     &amp;lt;/entity&amp;gt;&lt;br /&gt;    &amp;lt;/enrichment&amp;gt;&lt;br /&gt;   &amp;lt;/business-model&amp;gt;&lt;br /&gt;  &amp;lt;/model&amp;gt;&lt;br /&gt;  &amp;lt;targets&amp;gt;&lt;br /&gt;   &amp;lt;!-- openxava --&amp;gt;&lt;br /&gt;   &amp;lt;target refname="OpenXava" name="OpenXava"&lt;br /&gt;    fileName="mp-template-config-openxava-last-features.xml"&lt;br /&gt;    outputdir-root="../../DEV/output/openxava/conference"&lt;br /&gt;    templatedir-root="../../template/framework/openxava"&amp;gt;&lt;br /&gt;   &amp;lt;/target&amp;gt;&lt;br /&gt;&lt;br /&gt;   &amp;lt;target refname="JPA2-LIB" fileName="mp-template-config-JPA2-LIB.xml"&lt;br /&gt;    templatedir-root="../../template/framework/jpa"&amp;gt;&lt;br /&gt;   &amp;lt;/target&amp;gt;&lt;br /&gt;   &lt;br /&gt;   &amp;lt;target refname="BSLA-LIB" fileName="mp-template-config-bsla-LIB-features.xml"&lt;br /&gt;    templatedir-root="../../template/framework/bsla"&amp;gt;&lt;br /&gt;   &amp;lt;/target&amp;gt;&lt;br /&gt;&lt;br /&gt;   &amp;lt;target refname="CACHE-LIB" &lt;br /&gt;      fileName="mp-template-config-CACHE-LIB.xml" &lt;br /&gt;      templatedir-root="../../template/framework/cache"&amp;gt;&lt;br /&gt;   &amp;lt;/target&amp;gt;&lt;br /&gt;               &lt;br /&gt;  &amp;lt;/targets&amp;gt;&lt;br /&gt; &amp;lt;/configuration&amp;gt;&lt;br /&gt;&amp;lt;/generator-config&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;Test&lt;/span&gt;&lt;br /&gt;To ensure that the caching is working properly:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Enable hibernate logging. Add the following snippet as extra properties in persistence.xml.&lt;/li&gt;&lt;/ul&gt;&lt;pre class="xml" name="code"&gt;            &amp;lt;property name="hibernate.show_sql" value="true" /&amp;gt;&lt;br /&gt;            &amp;lt;property name="hibernate.format_sql" value="true" /&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;navigate to an entity that reference country (example Address)&lt;/li&gt;&lt;li&gt;When you view the detail of this entity you will notice that there is a load of the associated entity 'country'&lt;/li&gt;&lt;li&gt;But the second time you access to the details of this entity (or another entity referencing the same country instance), the country is not loaded twice from the database.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8723196641810122152-705883891423286727?l=minuteproject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://minuteproject.blogspot.com/feeds/705883891423286727/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://minuteproject.blogspot.com/2011/12/adding-ehcache-to-openxava-application.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/705883891423286727'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/705883891423286727'/><link rel='alternate' type='text/html' href='http://minuteproject.blogspot.com/2011/12/adding-ehcache-to-openxava-application.html' title='Adding Ehcache to Openxava application'/><author><name>florian</name><uri>http://www.blogger.com/profile/04083442568354390924</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8723196641810122152.post-4074647363702067209</id><published>2011-11-22T01:19:00.001-08:00</published><updated>2011-11-22T02:16:30.887-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JEE'/><category scheme='http://www.blogger.com/atom/ns#' term='telosys'/><category scheme='http://www.blogger.com/atom/ns#' term='rad'/><category scheme='http://www.blogger.com/atom/ns#' term='minuteproject'/><category scheme='http://www.blogger.com/atom/ns#' term='code generator'/><category scheme='http://www.blogger.com/atom/ns#' term='reverse-engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='database'/><title type='text'>MinuteProject Telosys impedance matching</title><content type='html'>This article is to review couple of technical points of both generators, and see the different possibilities of integration.&lt;br /&gt;My perception of Telosys is for the moment limited to what I learned at &lt;a href="http://www.devoxx.com/display/DV11/A+pragmatic+scaffolding+approach+to+build+Java+Web+Applications+in+few+minutes"&gt;Devoxx presentation&lt;/a&gt; and what I've tried, so if I miss things, be keen to notify.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;Telosys&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Code generator&lt;/li&gt;&lt;li&gt;Based on DB&lt;/li&gt;&lt;li&gt;Performs enrichment via GUI(Eclispe plugin) in a phase called repository&lt;/li&gt;&lt;li&gt;Generates for a target framework (JEE, Ajax) developped by Telosys Team&lt;/li&gt;&lt;li&gt;Generates artefacts for entities (table)&amp;nbsp;&lt;/li&gt;&lt;li&gt;Metadata of template (name, ...) are store in text file &lt;/li&gt;&lt;li&gt;Use Velocity as a template rendering engine&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size: large;"&gt;Telosys goodies&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt; JPA2 artefacts handle one2one relationship (not yet covered by minuteproject)&lt;/li&gt;&lt;li&gt;Telosys Plugin makes enrichment easy&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size: large;"&gt;Telosys neural&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Targeting a specific 'Telosys Framework' solution as pros and cons&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Pros&amp;nbsp;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;fully customized&lt;/li&gt;&lt;li&gt;all in one inside IDE&lt;/li&gt;&lt;/ul&gt;&lt;li&gt; Cons&amp;nbsp;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;dev. burden on a team&lt;/li&gt;&lt;li&gt;no market place recognition&lt;/li&gt;&lt;li&gt;reusability of templates might be poor&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;span style="font-size: x-large;"&gt;Minuteproject&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Code generator&lt;/li&gt;&lt;li&gt;Based on DB and WSDL based (next release: 0.7)&lt;/li&gt;&lt;li&gt;Performs enrichment via Configuration file or via a console&lt;/li&gt;&lt;li&gt;Generates for a range of &lt;a href="http://minuteproject.blogspot.com/2011/11/minuteproject-track-overview-release-06.html"&gt;market-place technologies&lt;/a&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Spring/hibernate/ibatis/JPA1/JPA2&lt;/li&gt;&lt;li&gt;Openxava&lt;/li&gt;&lt;li&gt;Play&lt;/li&gt;&lt;li&gt;Grails&lt;/li&gt;&lt;li&gt;Roo&lt;/li&gt;&lt;li&gt;REST&lt;/li&gt;&lt;li&gt;Primefaces&lt;/li&gt;&lt;li&gt;FitNesse &lt;/li&gt;&lt;li&gt;...&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Generate for artifacts at 6 levels&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Entity (tables/views)&lt;/li&gt;&lt;li&gt;Field&lt;/li&gt;&lt;li&gt;Package&lt;/li&gt;&lt;li&gt;Model&lt;/li&gt;&lt;li&gt;StoredProc&lt;/li&gt;&lt;li&gt;Application&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Generated code can be updated and modifications are kept over consecutive generation&lt;/li&gt;&lt;li&gt;Metadata of template (name, 20 other attributes) are store in xml file&amp;nbsp; &lt;/li&gt;&lt;li&gt;Possibility to define convention:&lt;/li&gt;&lt;ul&gt;&lt;li&gt; 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'.&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Use Velocity as a template rendering engine&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size: x-large;"&gt;Integration investigation tracks&lt;/span&gt;&lt;br /&gt;Here are couple of feasible tracks under investigation:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Integrate Minuteproject tracks into Telosys&lt;/li&gt;&lt;li&gt;Add Telosys target as a MinuteProject 4 Telosys track&lt;/li&gt;&lt;li&gt;Add Telosys Plugin over Minuteproject generator&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8723196641810122152-4074647363702067209?l=minuteproject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://minuteproject.blogspot.com/feeds/4074647363702067209/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://minuteproject.blogspot.com/2011/11/minuteproject-telosys-impedance.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/4074647363702067209'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/4074647363702067209'/><link rel='alternate' type='text/html' href='http://minuteproject.blogspot.com/2011/11/minuteproject-telosys-impedance.html' title='MinuteProject Telosys impedance matching'/><author><name>florian</name><uri>http://www.blogger.com/profile/04083442568354390924</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8723196641810122152.post-6994699097326033603</id><published>2011-11-15T02:13:00.001-08:00</published><updated>2011-11-15T02:22:15.664-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='fitnesse'/><category scheme='http://www.blogger.com/atom/ns#' term='rest'/><category scheme='http://www.blogger.com/atom/ns#' term='play'/><category scheme='http://www.blogger.com/atom/ns#' term='ibatis'/><category scheme='http://www.blogger.com/atom/ns#' term='ejb'/><category scheme='http://www.blogger.com/atom/ns#' term='primefaces'/><category scheme='http://www.blogger.com/atom/ns#' term='openxava'/><category scheme='http://www.blogger.com/atom/ns#' term='jpa2'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='jsf'/><category scheme='http://www.blogger.com/atom/ns#' term='cdi'/><title type='text'>MinuteProject Track overview release 0.6</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-9_BPoinofqA/TsI7WPMuewI/AAAAAAAAAFE/suHjBaYxT9A/s1600/MP-Track-overview-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="388" src="http://3.bp.blogspot.com/-9_BPoinofqA/TsI7WPMuewI/AAAAAAAAAFE/suHjBaYxT9A/s640/MP-Track-overview-2.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8723196641810122152-6994699097326033603?l=minuteproject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://minuteproject.blogspot.com/feeds/6994699097326033603/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://minuteproject.blogspot.com/2011/11/minuteproject-track-overview-release-06.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/6994699097326033603'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/6994699097326033603'/><link rel='alternate' type='text/html' href='http://minuteproject.blogspot.com/2011/11/minuteproject-track-overview-release-06.html' title='MinuteProject Track overview release 0.6'/><author><name>florian</name><uri>http://www.blogger.com/profile/04083442568354390924</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-9_BPoinofqA/TsI7WPMuewI/AAAAAAAAAFE/suHjBaYxT9A/s72-c/MP-Track-overview-2.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8723196641810122152.post-197089882342938851</id><published>2011-10-31T12:00:00.000-07:00</published><updated>2011-11-14T01:11:24.383-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fitnesse'/><category scheme='http://www.blogger.com/atom/ns#' term='crud'/><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='productivity'/><category scheme='http://www.blogger.com/atom/ns#' term='rad'/><category scheme='http://www.blogger.com/atom/ns#' term='reverse-engineering'/><title type='text'>FitNessize your JEE dev with minuteproject</title><content type='html'>&lt;b style="color: red;"&gt;&lt;/b&gt;&lt;br /&gt;&lt;div&gt;This article shows you how-to setup FitNesse in your development environment when dealing with Relation Database CRUD operations. MinuteProject 4 FitNesse generates entire set of FitNesse wiki pages and associated java fixtures allowing you to reset the database as well as performing intuitively CRUD operations on top of tables and Select on top of views.&lt;br /&gt;To illustrate this MinuteProject track, the Database used comes from the &lt;a href="http://code.google.com/p/lazuly/"&gt;Lazuly showcase&lt;/a&gt;. &lt;br /&gt;The sources can be found under &lt;a href="http://code.google.com/p/lazuly/source/browse/#svn%2Ftrunk%2Flazuly-fitnesse"&gt;lazuly-fitnesse&lt;/a&gt;.&lt;br /&gt;This page will show you:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;FitNesse + Minuteproject operating mechanism in Agile development&lt;/li&gt;&lt;li&gt;How-to Generate CRUD fixture&lt;/li&gt;&lt;li&gt;Integrate then in your own scenario to gain QA &lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size: x-large;"&gt;Overview&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-50Mqm8FOPxs/Tr015Fo1u1I/AAAAAAAAADM/CgT68GWPd00/s1600/MP+4+Fitnesse-operating-principle.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="459" src="http://3.bp.blogspot.com/-50Mqm8FOPxs/Tr015Fo1u1I/AAAAAAAAADM/CgT68GWPd00/s640/MP+4+Fitnesse-operating-principle.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;Install FitNesse and Generate A Custom CRUD wiki for you model&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Prerequisites&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Use Java 6&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;Install Lazuly DB (sql script &lt;a href="http://code.google.com/p/lazuly/source/browse/trunk/conference-db/conference-db-mysql-0.1.sql"&gt;here&lt;/a&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size: large;"&gt;Installation&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;Download &lt;a href="http://www.blogger.com/goog_1093589749"&gt;FitNesse&lt;/a&gt;&lt;/span&gt;&lt;a href="http://fitnesse.org/"&gt; &lt;/a&gt;&lt;/span&gt;&lt;br /&gt;Execute java -jar fitnesse.jar&lt;br /&gt;On a browser go to &lt;a href="http://locahost/"&gt;http://localhost&lt;/a&gt; to view the FitNesse wiki &lt;br /&gt;&lt;span style="font-size: large;"&gt;Generate a FitNesse wiki for your model&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;Download &lt;a href="http://sourceforge.net/projects/minuteproject/files/"&gt;MinuteProject&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;Generate &lt;/span&gt;&lt;/span&gt;using the following minuteproject configuration script: &lt;span class="ifClosed" id="crumb_links"&gt;mp-config-LAZULY-FITNESSE.xml&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Set this script in &lt;mp_home&gt;/mywork/config and run generate-model.(cmd/sh) &lt;span class="ifClosed" id="crumb_links"&gt;mp-config-LAZULY-FITNESSE.xml&lt;/span&gt;&lt;/mp_home&gt;&lt;/li&gt;&lt;/ul&gt;The &lt;span class="ifClosed" id="crumb_links"&gt;mp-config-LAZULY-FITNESSE.xml configuration file&lt;/span&gt;&lt;br /&gt;&lt;pre class="java" name="code"&gt;&amp;lt;!DOCTYPE root&amp;gt;&lt;br /&gt;&amp;lt;generator-config&amp;gt;&lt;br /&gt; &amp;lt;configuration&amp;gt;&lt;br /&gt;  &amp;lt;conventions&amp;gt;&lt;br /&gt;   &amp;lt;target-convention type="enable-updatable-code-feature" /&amp;gt;&lt;br /&gt;  &amp;lt;/conventions&amp;gt; &lt;br /&gt;  &amp;lt;model name="conference" version="1.0" package-root="net.sf.mp.demo"&amp;gt;&lt;br /&gt;   &amp;lt;data-model&amp;gt;&lt;br /&gt;    &amp;lt;dataSource&amp;gt;&lt;br /&gt;     &amp;lt;driverClassName&amp;gt;org.gjt.mm.mysql.Driver&amp;lt;/driverClassName&amp;gt;&lt;br /&gt;     &amp;lt;url&amp;gt;jdbc:mysql://127.0.0.1:3306/conference&amp;lt;/url&amp;gt;&lt;br /&gt;     &amp;lt;username&amp;gt;root&amp;lt;/username&amp;gt;&lt;br /&gt;     &amp;lt;password&amp;gt;mysql&amp;lt;/password&amp;gt;&lt;br /&gt;    &amp;lt;/dataSource&amp;gt;&lt;br /&gt;   &amp;lt;/data-model&amp;gt;&lt;br /&gt;   &amp;lt;business-model&amp;gt;&lt;br /&gt; ﻿  ﻿  ﻿  ﻿  &amp;lt;business-package default="conference"&amp;gt;&lt;br /&gt; ﻿  ﻿  ﻿  ﻿      &amp;lt;condition type="package" startsWith="STAT" result="statistics"&amp;gt;&amp;lt;/condition&amp;gt;&lt;br /&gt; ﻿  ﻿  ﻿  ﻿      &amp;lt;condition type="package" startsWith="COUNTRY" result="admin"&amp;gt;&amp;lt;/condition&amp;gt;&lt;br /&gt; ﻿  ﻿  ﻿  ﻿      &amp;lt;condition type="package" startsWith="ROLE" result="admin"&amp;gt;&amp;lt;/condition&amp;gt;﻿  ﻿  ﻿  ﻿  &lt;br /&gt; ﻿  ﻿  ﻿  ﻿  &amp;lt;/business-package&amp;gt;   &lt;br /&gt;    &amp;lt;enrichment&amp;gt;&lt;br /&gt;     &amp;lt;conventions&amp;gt;&lt;br /&gt;         &amp;lt;view-primary-key-convention &lt;br /&gt;            type="apply-default-primary-key-otherwise-first-one" &lt;br /&gt;            default-primary-key-names="ID" &amp;gt;&lt;br /&gt;         &amp;lt;/view-primary-key-convention&amp;gt;&lt;br /&gt;     &amp;lt;/conventions&amp;gt;&lt;br /&gt;    &amp;lt;/enrichment&amp;gt;&lt;br /&gt;   &amp;lt;/business-model&amp;gt;&lt;br /&gt;  &amp;lt;/model&amp;gt;&lt;br /&gt;  &amp;lt;targets&amp;gt; &lt;br /&gt;   &amp;lt;target refname="FitNesse" &lt;br /&gt;      name="default" &lt;br /&gt;      fileName="mp-template-config-fitnesse.xml" &lt;br /&gt;      outputdir-root="D:/DEV/LAZULY/lazuly-fitnesse"&lt;br /&gt;      templatedir-root="../../template/framework/fitnesse"&amp;gt;&lt;br /&gt;   &amp;lt;/target&amp;gt; &lt;br /&gt;   &amp;lt;target refname="LIB" &lt;br /&gt;      fileName="mp-template-config-bsla-LIB-features.xml" &lt;br /&gt;      templatedir-root="../../template/framework/bsla"&amp;gt;&lt;br /&gt;   &amp;lt;/target&amp;gt;&lt;br /&gt;  &amp;lt;/targets&amp;gt;  &lt;br /&gt;&lt;br /&gt; &amp;lt;/configuration&amp;gt;&lt;br /&gt;&amp;lt;/generator-config&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;table cellpadding="0" cellspacing="0" class="list" id="nav_and_rev"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="src_crumbs src_nav" nowrap="nowrap" width="33%"&gt;&lt;br /&gt;This configuration describes:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;where the model stands&lt;/li&gt;&lt;li&gt;what track (fitnesse track) to use.&lt;/li&gt;&lt;li&gt;where to generate (here D:/DEV/LAZULY/lazuly-fitnesse)&lt;/li&gt;&lt;li&gt;that the artifact are updatable (i.e. you can modify some artefacts and your modification are kept over successive generations)&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Alternative Generation &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;Alternatively, you can use the MinuteProject Console:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;start console: &lt;mp_home&gt;/bin/start-console.(cmd/sh)&lt;/mp_home&gt;&lt;/li&gt;&lt;li&gt;Fill connection parameters, misc information&lt;/li&gt;&lt;li&gt;Choose target FitNesse&lt;/li&gt;&lt;li&gt;Click Generate&lt;/li&gt;&lt;/ul&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-HrYegNf5wh8/TsDXiqil_rI/AAAAAAAAAE8/nz6VobKmDr8/s1600/FitNesse_Lazuly_MP_Console.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="http://3.bp.blogspot.com/-HrYegNf5wh8/TsDXiqil_rI/AAAAAAAAAE8/nz6VobKmDr8/s400/FitNesse_Lazuly_MP_Console.png" width="396" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;ul&gt;&lt;/ul&gt;&lt;/td&gt;   &lt;td align="center" nowrap="nowrap" width="33%"&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;span style="font-size: large;"&gt;What is generated&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Wiki Fixtures for CRUD operations&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://4.bp.blogspot.com/-U7f_vYn1hxw/Tr0_kcKDttI/AAAAAAAAAD0/Lo6qoME-fNk/s1600/Lazuly_Wiki_artifact.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://4.bp.blogspot.com/-U7f_vYn1hxw/Tr0_kcKDttI/AAAAAAAAAD0/Lo6qoME-fNk/s320/Lazuly_Wiki_artifact.png" width="155" /&gt;&lt;/a&gt;&lt;br /&gt;Wiki source to be copied in your FitNesse Root Directory &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;FitNesse CRUD Wiki generated for you model.&lt;br /&gt;Pick-up the snippet you need to:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;SetUp you DB model&lt;/li&gt;&lt;li&gt;Perform sanity check&amp;nbsp;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;after X UCs in a scenario, are my data correctly stored? &lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;ul&gt;&lt;ul&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;a href="http://2.bp.blogspot.com/-3H33Q-wkVrE/Tr0_jA2d4eI/AAAAAAAAADg/o3iYpa4WgRs/s1600/Lazuly_Fitnesse_Select_wiki.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="251" src="http://2.bp.blogspot.com/-3H33Q-wkVrE/Tr0_jA2d4eI/AAAAAAAAADg/o3iYpa4WgRs/s400/Lazuly_Fitnesse_Select_wiki.png" width="400" /&gt;&lt;/a&gt;Lazuly FitNesse subwiki for select operations&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-ExO0DIM426o/Tr0_jmfVEQI/AAAAAAAAADo/BL-MQjLpwco/s1600/Lazuly_Select_snippet_on_view.png" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="356" src="http://1.bp.blogspot.com/-ExO0DIM426o/Tr0_jmfVEQI/AAAAAAAAADo/BL-MQjLpwco/s400/Lazuly_Select_snippet_on_view.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/-eVRwQ06HlH4/Tr0_k3Puj4I/AAAAAAAAAD8/AHiuFCjKzK8/s1600/Lazuly-crud-wiki.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="242" src="http://1.bp.blogspot.com/-eVRwQ06HlH4/Tr0_k3Puj4I/AAAAAAAAAD8/AHiuFCjKzK8/s400/Lazuly-crud-wiki.png" width="400" /&gt;&lt;/a&gt;&lt;br /&gt;Details of Select wiki fixtures for view 'stat_mb_by_role'&lt;br /&gt;&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Lazuly FitNesse subwiki for insert update delete operations&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/-jr7YGu2YD80/Tr0_iZvrPRI/AAAAAAAAADc/81OQ_TmAGZg/s1600/LAzuly_Fitness_CRUD_TestAddress.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="http://2.bp.blogspot.com/-jr7YGu2YD80/Tr0_iZvrPRI/AAAAAAAAADc/81OQ_TmAGZg/s400/LAzuly_Fitness_CRUD_TestAddress.png" width="398" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Details of Insert, Update, Delete wiki fixtures for table 'address'&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-ExO0DIM426o/Tr0_jmfVEQI/AAAAAAAAADo/BL-MQjLpwco/s1600/Lazuly_Select_snippet_on_view.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;Associated Java Fixture&amp;nbsp;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-6HWZjK4mg48/Tr0_h5Vd3rI/AAAAAAAAADU/xv9iIvjK2xQ/s1600/Fitnesse_Lazuly_fixture.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="http://2.bp.blogspot.com/-6HWZjK4mg48/Tr0_h5Vd3rI/AAAAAAAAADU/xv9iIvjK2xQ/s400/Fitnesse_Lazuly_fixture.png" width="331" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;Assemble for your need&lt;/span&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;Build Java Fixture Project&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;Compile the code in an IDE&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;add src-generated to your source directories&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;add MP 4 FitNesse depencies libra&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;ries&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;For the moment they are provided in MP package under &lt;mp_home&gt;/target/fitnesse/ and &lt;/mp_home&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;&lt;mp_home&gt;/target/fitnesse/dep&lt;/mp_home&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;Lazuly-fitnesse is shipped with an eclipse project that compiles the code to &lt;lazuly-fitnesse&gt;/bin&lt;/lazuly-fitnesse&gt;&lt;/li&gt;&lt;li&gt;The compilation directory is to be reference by the FitNesse wiki path directives.&lt;br /&gt;  &lt;/li&gt;&lt;/ul&gt;&lt;b&gt;SetUp FitNesse Lazuly Wiki&lt;/b&gt;&lt;br /&gt;Althought MinuteProject provides CRUD wiki ready to use, the purpose of this section is to setup a custom wiki that will be used for your UC.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Create your FitNesse Application Wiki HomePage&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Edit main page add a section called 'FitNesseLazulyScenario'&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Add snippet [[Lazuly][FitNesse.LazulyScenario]]&lt;br /&gt;    &lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;li&gt;Click on Lazuly ? or go to http://localhost/FitNesse.LazulyScenario&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Compose a simple structure&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Simple structure proposal&lt;/li&gt;&lt;ul&gt;&lt;li&gt;HomePage section (define the path to use)&lt;br /&gt;  &lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Setup section (Used to reset DB)&lt;/li&gt;&lt;li&gt;Data Definition section (Used to define common variables referenced in scenario)&lt;/li&gt;&lt;li&gt;Populate section (Used to initialize DB with data)&lt;/li&gt;&lt;li&gt;Couple of UC section&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;span style="font-size: x-large;"&gt;Write a sample scenario&lt;/span&gt;&lt;br /&gt;This scenario will populate couple of tables of the Lazuly DB and check if the result expected in the views is correct.&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;HomePage section&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;Defines&amp;nbsp; &lt;br /&gt;&lt;ul&gt;&lt;li&gt;different pages (SetUp, VariableDefinition, UC sections)&amp;nbsp;&lt;/li&gt;&lt;li&gt;classpath &lt;/li&gt;&lt;/ul&gt;&lt;b&gt;&lt;/b&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/-ssAAsxRuQ0g/Tr7lUWqiAoI/AAAAAAAAAEM/k6CxX79hkFo/s1600/FitNesse_Lazuly_Home.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="353" src="http://4.bp.blogspot.com/-ssAAsxRuQ0g/Tr7lUWqiAoI/AAAAAAAAAEM/k6CxX79hkFo/s400/FitNesse_Lazuly_Home.png" width="400" /&gt;&lt;/a&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;Setup section&lt;/span&gt;&amp;nbsp;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Reset Database&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Reference Reset script executed by Scriptella (etl.xml)&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Adapt the variable &lt;span class="meta"&gt;resetfilepathvar&lt;/span&gt; to point to your file path.&lt;br /&gt; &lt;/li&gt;&lt;/ul&gt;&lt;li&gt;etl.xml references 3 sql script&lt;/li&gt;&lt;ul&gt;&lt;li&gt;reset_db.sql that proposed a Delete statement per table&lt;/li&gt;&lt;ul&gt;&lt;li&gt;It can be altered since the delete order might not be correct&lt;/li&gt;&lt;li&gt;In this case please add -- MP-MANAGED-STOP-GENERATING to prevent your modification to be lost for consecutive generation&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;insert_reference_data.sql&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Add the data you wish&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;commit.sql that just perform a commit&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;li&gt;Connection parameter to point to the database that include&lt;/li&gt;&lt;ul&gt;&lt;li&gt;DB URL&lt;/li&gt;&lt;li&gt;JDBC driver&lt;/li&gt;&lt;li&gt;Username&lt;/li&gt;&lt;li&gt;Password&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;All this code is generate in &lt;lazuly-fitnesse&gt;/ConferenceFitnesseWikiSetup/content.txt. It can also be copied from http://localhost/ConferenceFitnesseWikiSetup&lt;/lazuly-fitnesse&gt;&lt;/li&gt;&lt;/ul&gt;&lt;a href="http://1.bp.blogspot.com/-7n3sPQiJICE/Tr7ljjEXS0I/AAAAAAAAAEU/hRsSZm7ZTtg/s1600/Fitnesse_Lazuly_setup.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="257" src="http://1.bp.blogspot.com/-7n3sPQiJICE/Tr7ljjEXS0I/AAAAAAAAAEU/hRsSZm7ZTtg/s400/Fitnesse_Lazuly_setup.png" width="400" /&gt;&lt;/a&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Variable Definition section&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Use Fitnesse directive !define to add relevant variable name for your scenario&lt;/div&gt;&lt;div&gt;Those variables will be later refered in your UCs&lt;b&gt;&lt;/b&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/-5Ttfb98gKvU/Tr7rgkTgHoI/AAAAAAAAAEc/Sd4gw5UpMSc/s1600/FitNesse_Lazuly_variable_definition.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="http://1.bp.blogspot.com/-5Ttfb98gKvU/Tr7rgkTgHoI/AAAAAAAAAEc/Sd4gw5UpMSc/s400/FitNesse_Lazuly_variable_definition.png" width="372" /&gt;&lt;/a&gt;&lt;b&gt; &lt;/b&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Populate section&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;The SetUp page is automatically included at the beginning of your scenario.&lt;/div&gt;&lt;div&gt;But you have to reference the Variable Definition section. For that use the FitNesse directive !include (!include VariableDefinition)&lt;br /&gt;&lt;br /&gt;Pick-up CRUD snippet from MP generated FitNesse Wiki to create you own customed DB initialization.&lt;br /&gt;Insert reference data Country, Role&lt;br /&gt;Insert business data: Address, Conference, ConferenceMember&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-DR8du0LxYoA/Tr7rsUbUSNI/AAAAAAAAAEk/kavjFdD8ws4/s1600/FitNesse_Lazuly_Populate_with_Data_.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="383" src="http://2.bp.blogspot.com/-DR8du0LxYoA/Tr7rsUbUSNI/AAAAAAAAAEk/kavjFdD8ws4/s400/FitNesse_Lazuly_Populate_with_Data_.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-KFqz5utt128/Tr7rtBQTGII/AAAAAAAAAEs/-ja2lY8lafM/s1600/FitNesse_Lazuly_Populate_with_Data_2.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="350" src="http://3.bp.blogspot.com/-KFqz5utt128/Tr7rtBQTGII/AAAAAAAAAEs/-ja2lY8lafM/s400/FitNesse_Lazuly_Populate_with_Data_2.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;UC Check section&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;Pick-up CRUD snippet from MP generated FitNesse Wiki to create you own customed DB initialization.&lt;br /&gt;In this case, I simply check that the data are stored correctly.&lt;br /&gt;There is a view that gather BI information and I use it to validate the correctness of the information.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-J0Os-ywnYIQ/Tr7r9FU65dI/AAAAAAAAAE0/iZPrVy4AwRg/s1600/FitNesse_Lazuly_Sanity_check.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="305" src="http://4.bp.blogspot.com/-J0Os-ywnYIQ/Tr7r9FU65dI/AAAAAAAAAE0/iZPrVy4AwRg/s400/FitNesse_Lazuly_Sanity_check.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Conclusion&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;This example shows that you can have use very easily CRUD fitnesse fixture (Zero LOC of development are required) customized for your data model.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;To sum-up, here are the main points:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;Reset DB&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;Initialize DB&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;Perform sanity check&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;Set-up FitNesse for your hadoc UCs for JEE data centric application&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-i2I6t5B73Uc/Tr60iOYfsdI/AAAAAAAAAEE/enHr62SQWag/s1600/bumperSticker.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="122" src="http://2.bp.blogspot.com/-i2I6t5B73Uc/Tr60iOYfsdI/AAAAAAAAAEE/enHr62SQWag/s400/bumperSticker.gif" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;MinuteProject Spin-offs&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;At this point on you can guarante that the data retrieved from the view are correct.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;That means that you have QA on your model.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;If the views have a field containing unique values then you can benefit of MinuteProject spin-off i.e. use other track to generate out-of-the-box:&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;Web2.0 application in Openxava on top of views. See on this blog &lt;a href="http://minuteproject.blogspot.com/2011/09/sql-select-to-web-application-in-couple.html"&gt;the following article&lt;/a&gt;&amp;nbsp;&lt;/li&gt;&lt;li&gt;REST application.&lt;/li&gt;&lt;li&gt;Web service application.&lt;/li&gt;&lt;/ul&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;For Real UCs&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Here the UCs demonstrated concern only CRUD operations on top of DB entities.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;2 next articles in prepartion will show how to integrate with:&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;JPA2 ORM backend&lt;/li&gt;&lt;li&gt;Spring/JPA/Hibernate backend&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-size: x-large;"&gt;Additional information&lt;/span&gt;&lt;br /&gt;&lt;a href="http://minuteproject.wikispaces.com/fitnesse"&gt;MinuteProject 4 FitNesse&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8723196641810122152-197089882342938851?l=minuteproject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://minuteproject.blogspot.com/feeds/197089882342938851/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://minuteproject.blogspot.com/2011/10/fitnessize-your-jee-dev-with.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/197089882342938851'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/197089882342938851'/><link rel='alternate' type='text/html' href='http://minuteproject.blogspot.com/2011/10/fitnessize-your-jee-dev-with.html' title='FitNessize your JEE dev with minuteproject'/><author><name>florian</name><uri>http://www.blogger.com/profile/04083442568354390924</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-50Mqm8FOPxs/Tr015Fo1u1I/AAAAAAAAADM/CgT68GWPd00/s72-c/MP+4+Fitnesse-operating-principle.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8723196641810122152.post-2774501365615224373</id><published>2011-10-14T02:44:00.000-07:00</published><updated>2011-10-14T03:34:40.881-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='metro'/><category scheme='http://www.blogger.com/atom/ns#' term='minuteproject'/><category scheme='http://www.blogger.com/atom/ns#' term='jaxws'/><category scheme='http://www.blogger.com/atom/ns#' term='wsdl'/><category scheme='http://www.blogger.com/atom/ns#' term='soa'/><title type='text'>MinuteProject goes SOA</title><content type='html'>Minuteproject "traditional" activity is to generate artifacts based on a Relation Database (RDBMS).&lt;br /&gt;Meanwhile RDBMS is not the only type of standard structured information that is available on the market.&lt;br /&gt;WSDL and WADL format describes a standard way to integrate systems with open technologies.&lt;br /&gt;WSDL is widely used for webservice with SOAP messages integration promoted by the &lt;a href="http://www.oasis-open.org/"&gt;OASIS&lt;/a&gt; standards.&lt;br /&gt;WADL is the representation of the REST contract offered by an application.&lt;br /&gt;&lt;br /&gt;Minuteproject is integrating the &lt;a href="http://metro.java.net/"&gt;metro&lt;/a&gt; API to parse wsdl and get a WsdlModel to generate artifacts upon.&lt;br /&gt;&lt;br /&gt;The integration with metro is fairly simple&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;package metro;&lt;br /&gt;&lt;br /&gt;import java.io.File;&lt;br /&gt;&lt;br /&gt;import com.sun.tools.ws.processor.model.Model;&lt;br /&gt;import com.sun.tools.ws.processor.modeler.wsdl.WSDLModeler;&lt;br /&gt;import com.sun.tools.ws.wscompile.ErrorReceiverFilter;&lt;br /&gt;import com.sun.tools.ws.wscompile.WsimportOptions;&lt;br /&gt;&lt;br /&gt;public class SimpleWSDLModel {&lt;br /&gt;&lt;br /&gt;public static void main(String[] args) {&lt;br /&gt; ErrorReceiverFilter receiver = new ErrorReceiverFilter();&lt;br /&gt; WsimportOptions options = new WsimportOptions();&lt;br /&gt; options.addWSDL(new File(args[0]));&lt;br /&gt; WSDLModeler wsdlModeler = new WSDLModeler(options, receiver);&lt;br /&gt; Model wsdlModel = wsdlModeler.buildModel();&lt;br /&gt; System.out.println(wsdlModel);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;When giving a wsdl location file-system or URL, then Metro provides a wsdlModel that contains all the wsdl structure in memory and xml schema elements converted into their jaxb correspondance.&lt;br /&gt;This eases the integration into minuteproject since the elements (jaxb classes, service, port, binding) are ready to be set into templates.&lt;br /&gt;The goal for minuteproject is not to re-do the JAX-WS part of Metro available by wsimport command but to add a set of new tracks and artifacts to reduce the development effort.&lt;br /&gt;&lt;br /&gt;Some tracks could be:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;SOA FitNesse track: providing a FitNesse wiki with fixture (slim) to test the webservice implementation (without deployment)&lt;/li&gt;&lt;li&gt;Screens: JSF, vaadin for webservice client&lt;/li&gt;&lt;li&gt;WebService implementation&lt;/li&gt;&lt;li&gt;...&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;This functionality will be available in the next release 0.7.&lt;br /&gt;The SOA tracks will be added one at time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8723196641810122152-2774501365615224373?l=minuteproject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://minuteproject.blogspot.com/feeds/2774501365615224373/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://minuteproject.blogspot.com/2011/10/minuteproject-goes-soa.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/2774501365615224373'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/2774501365615224373'/><link rel='alternate' type='text/html' href='http://minuteproject.blogspot.com/2011/10/minuteproject-goes-soa.html' title='MinuteProject goes SOA'/><author><name>florian</name><uri>http://www.blogger.com/profile/04083442568354390924</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8723196641810122152.post-6364727596531816353</id><published>2011-09-18T01:25:00.000-07:00</published><updated>2011-10-14T03:01:39.188-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vaadin'/><category scheme='http://www.blogger.com/atom/ns#' term='rest'/><category scheme='http://www.blogger.com/atom/ns#' term='openxava'/><category scheme='http://www.blogger.com/atom/ns#' term='minuteproject'/><category scheme='http://www.blogger.com/atom/ns#' term='jaxb'/><category scheme='http://www.blogger.com/atom/ns#' term='jpa2'/><category scheme='http://www.blogger.com/atom/ns#' term='jaxrs'/><title type='text'>RESTication of Openxava app and Vaadin client</title><content type='html'>&lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;Article under construction&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The purpose of this article is to provide REST interface for Openxava (OX) application.&lt;br /&gt;It shows how-to&lt;br /&gt;&lt;ul&gt;&lt;li&gt;integrate &lt;a href="http://jersey.java.net/"&gt;jersey&lt;/a&gt; engine into the OX build&lt;/li&gt;&lt;li&gt;extends the JPA2 entities with JAXB and JAXRS annotations &lt;/li&gt;&lt;li&gt;write a little UC with methods that returns xml/json message&lt;/li&gt;&lt;li&gt;test it&lt;/li&gt;&lt;li&gt;Make a sample Vaadin client application for those REST services&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;To illustrate this, I will take an Openxava application generated by minuteproject (&lt;a href="http://minuteproject.blogspot.com/2011/09/sql-select-to-web-application-in-couple.html"&gt;http://minuteproject.blogspot.com/2011/09/sql-select-to-web-application-in-couple.html&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Integrate Jersey engine in OX build&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Jersey lib integration&lt;br /&gt;Add the following libraries in your project /web/WEB-INF/lib&lt;br /&gt;&lt;ul&gt;&lt;li&gt;jsr305-1.3.2.jar&lt;/li&gt;&lt;li&gt;jersey-core-1.9-ea03.jar&lt;/li&gt;&lt;li&gt;jersey-server-1.9-ea03.jar&lt;/li&gt;&lt;li&gt;asm-3.1.jar (although asm.jar is shipped with OX this version is to used)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Here the dependency is on jersey-server-1.9-ea03&lt;br /&gt;&lt;br /&gt;In your OX project add the file &lt;span style="font-weight: bold;"&gt;servlets.xml&lt;/span&gt; into /web/WEB-INF&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="xml"&gt;   &amp;lt;servlet&amp;gt;&lt;br /&gt;&amp;lt;servlet-name&amp;gt;petshop Jersey Web Application&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;&amp;lt;servlet-class&amp;gt;com.sun.jersey.spi.container.servlet.ServletContainer&amp;lt;/servlet-class&amp;gt;&lt;br /&gt;&amp;lt;init-param&amp;gt;&lt;br /&gt;&amp;lt;param-name&amp;gt;com.sun.jersey.config.property.resourceConfigClass&amp;lt;/param-name&amp;gt;&lt;br /&gt;&amp;lt;param-value&amp;gt;com.sun.jersey.api.core.PackagesResourceConfig&amp;lt;/param-value&amp;gt;&lt;br /&gt;&amp;lt;/init-param&amp;gt;&lt;br /&gt;&amp;lt;init-param&amp;gt;&lt;br /&gt;&amp;lt;param-name&amp;gt;com.sun.jersey.config.property.packages&amp;lt;/param-name&amp;gt;&lt;br /&gt;&amp;lt;param-value&amp;gt;my.cool.report&amp;lt;/param-value&amp;gt;&lt;br /&gt;&amp;lt;/init-param&amp;gt;&lt;br /&gt;&amp;lt;load-on-startup&amp;gt;1&amp;lt;/load-on-startup&amp;gt;&lt;br /&gt;&amp;lt;/servlet&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;servlet-mapping&amp;gt;&lt;br /&gt;&amp;lt;servlet-name&amp;gt;petshop Jersey Web Application&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;&amp;lt;url-pattern&amp;gt;/rest/*&amp;lt;/url-pattern&amp;gt;&lt;br /&gt;&amp;lt;/servlet-mapping&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Openxava build takes what you define in servlets.xml file and insert it in the web.xml&lt;br /&gt;The snippet above specifies the following:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Jersey engine will parse the package for JAXRS annotation in the package "my.cool.report"&lt;/li&gt;&lt;li&gt;the context path used for REST will be /rest/*&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:180%;"&gt;JAXB &amp;amp; JAXRS integration&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Add Jaxb and Jaxrs annotation in OX jpa2 entities&lt;br /&gt;&lt;br /&gt;Class MyConferenceCoolReport&lt;br /&gt;&lt;pre name="code" class="java"&gt;package my.cool.report.conference.domain.report;&lt;br /&gt;&lt;br /&gt;import java.sql.*;&lt;br /&gt;import java.util.Date;&lt;br /&gt;import java.util.List;&lt;br /&gt;import java.util.ArrayList;&lt;br /&gt;import java.util.Set;&lt;br /&gt;import java.util.HashSet;&lt;br /&gt;&lt;br /&gt;import javax.persistence.*;&lt;br /&gt;import javax.ws.rs.*;&lt;br /&gt;import javax.ws.rs.core.*;&lt;br /&gt;import javax.xml.bind.annotation.*;&lt;br /&gt;&lt;br /&gt;import my.cool.report.conference.dto.report.*;&lt;br /&gt;&lt;br /&gt;import org.openxava.annotations.*;&lt;br /&gt;import org.openxava.jpa.*;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;*&lt;br /&gt;* &lt;p&gt;Title: MyConferenceCoolReport&lt;/p&gt;&lt;br /&gt;*&lt;br /&gt;* &lt;p&gt;Description: Domain Object describing a MyConferenceCoolReport entity&lt;/p&gt;&lt;br /&gt;*&lt;br /&gt;*/&lt;br /&gt;@Entity (name="MyConferenceCoolReport")&lt;br /&gt;@Table (name="my_conference_cool_report")&lt;br /&gt;@Views({&lt;br /&gt;@View(&lt;br /&gt;name="base",&lt;br /&gt;members=&lt;br /&gt;""&lt;br /&gt;+ "firstName  ; "&lt;br /&gt;+ "lastName  ; "&lt;br /&gt;+ "email  ; "&lt;br /&gt;+ "status  ; "&lt;br /&gt;+ "addressStreet1  ; "&lt;br /&gt;+ "addressStreet2  ; "&lt;br /&gt;+ "countryCode  ; "&lt;br /&gt;+ "conferenceName  ; "&lt;br /&gt;+ "conferenceBeginDate  ; "&lt;br /&gt;+ "conferenceEndDate  ; "&lt;br /&gt;),&lt;br /&gt;@View(&lt;br /&gt;name="Create",&lt;br /&gt;extendsView="base"&lt;br /&gt;),&lt;br /&gt;@View(&lt;br /&gt;name="Update",&lt;br /&gt;extendsView="base",&lt;br /&gt;members=&lt;br /&gt; ""&lt;br /&gt;),&lt;br /&gt;@View(extendsView="base",&lt;br /&gt;members=&lt;br /&gt; ""&lt;br /&gt;),&lt;br /&gt;@View(name="myConferenceCoolReportDEFAULT_VIEW",&lt;br /&gt;members=&lt;br /&gt; " id ;"&lt;br /&gt;+ "firstName  ; "&lt;br /&gt;+ "lastName  ; "&lt;br /&gt;+ "email  ; "&lt;br /&gt;+ "status  ; "&lt;br /&gt;+ "addressStreet1  ; "&lt;br /&gt;+ "addressStreet2  ; "&lt;br /&gt;+ "countryCode  ; "&lt;br /&gt;+ "conferenceName  ; "&lt;br /&gt;+ "conferenceBeginDate  ; "&lt;br /&gt;+ "conferenceEndDate  ; "&lt;br /&gt;)&lt;br /&gt;})&lt;br /&gt;&lt;br /&gt;@Tabs({&lt;br /&gt;@Tab(&lt;br /&gt;properties=&lt;br /&gt;" firstName "&lt;br /&gt;+",  lastName "&lt;br /&gt;+",  email "&lt;br /&gt;+",  status "&lt;br /&gt;+",  addressStreet1 "&lt;br /&gt;+",  addressStreet2 "&lt;br /&gt;+",  countryCode "&lt;br /&gt;+",  conferenceName "&lt;br /&gt;+",  conferenceBeginDate "&lt;br /&gt;+",  conferenceEndDate "&lt;br /&gt;)&lt;br /&gt;,&lt;br /&gt;@Tab(&lt;br /&gt;name = "MyConferenceCoolReportTab",&lt;br /&gt;properties=&lt;br /&gt;" firstName "&lt;br /&gt;+",  lastName "&lt;br /&gt;+",  email "&lt;br /&gt;+",  status "&lt;br /&gt;+",  addressStreet1 "&lt;br /&gt;+",  addressStreet2 "&lt;br /&gt;+",  countryCode "&lt;br /&gt;+",  conferenceName "&lt;br /&gt;+",  conferenceBeginDate "&lt;br /&gt;+",  conferenceEndDate "&lt;br /&gt;)&lt;br /&gt;,&lt;br /&gt;@Tab(&lt;br /&gt;name = "MyConferenceCoolReportTabWithRef",&lt;br /&gt;properties=&lt;br /&gt;" firstName "&lt;br /&gt;+",  lastName "&lt;br /&gt;+",  email "&lt;br /&gt;+",  status "&lt;br /&gt;+",  addressStreet1 "&lt;br /&gt;+",  addressStreet2 "&lt;br /&gt;+",  countryCode "&lt;br /&gt;+",  conferenceName "&lt;br /&gt;+",  conferenceBeginDate "&lt;br /&gt;+",  conferenceEndDate "&lt;br /&gt;)&lt;br /&gt;})&lt;br /&gt;@XmlAccessorType(XmlAccessType.FIELD)&lt;br /&gt;@XmlType&lt;br /&gt;@XmlRootElement&lt;br /&gt;@Path ("/myreports")&lt;br /&gt;public class MyConferenceCoolReport {&lt;br /&gt;&lt;br /&gt;@Hidden @Id @Column(name="id" )&lt;br /&gt;private Long id;&lt;br /&gt;&lt;br /&gt;@Column(name="first_name",  length=255, nullable=false,  unique=false)&lt;br /&gt;@Required&lt;br /&gt;private String firstName;&lt;br /&gt;@Column(name="last_name",  length=255, nullable=false,  unique=false)&lt;br /&gt;@Required&lt;br /&gt;private String lastName;&lt;br /&gt;@Column(name="email",  length=255, nullable=false,  unique=false)&lt;br /&gt;@Required&lt;br /&gt;private String email;&lt;br /&gt;@Column(name="status",  length=45, nullable=false,  unique=false)&lt;br /&gt;@Required&lt;br /&gt;private String status;&lt;br /&gt;@Column(name="address_street1",  length=255,  nullable=true,  unique=false)&lt;br /&gt;private String addressStreet1;&lt;br /&gt;@Column(name="address_street2",  length=255,  nullable=true,  unique=false)&lt;br /&gt;private String addressStreet2;&lt;br /&gt;@Column(name="country_code",  length=45, nullable=false,  unique=false)&lt;br /&gt;@Required&lt;br /&gt;private String countryCode;&lt;br /&gt;@Column(name="conference_name",  length=255, nullable=false,  unique=false)&lt;br /&gt;@Required&lt;br /&gt;private String conferenceName;&lt;br /&gt;@Column(name="conference_begin_date",    nullable=true,  unique=false)&lt;br /&gt;private Date conferenceBeginDate;&lt;br /&gt;@Column(name="conference_end_date",    nullable=true,  unique=false)&lt;br /&gt;private Date conferenceEndDate;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Default constructor&lt;br /&gt;*/&lt;br /&gt;public MyConferenceCoolReport() {&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public Long getId() {&lt;br /&gt;return id;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setId (Long id) {&lt;br /&gt;this.id =  id;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public String getFirstName() {&lt;br /&gt;return firstName;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setFirstName (String firstName) {&lt;br /&gt;this.firstName =  firstName;&lt;br /&gt;}&lt;br /&gt;public String getLastName() {&lt;br /&gt;return lastName;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setLastName (String lastName) {&lt;br /&gt;this.lastName =  lastName;&lt;br /&gt;}&lt;br /&gt;public String getEmail() {&lt;br /&gt;return email;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setEmail (String email) {&lt;br /&gt;this.email =  email;&lt;br /&gt;}&lt;br /&gt;public String getStatus() {&lt;br /&gt;return status;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setStatus (String status) {&lt;br /&gt;this.status =  status;&lt;br /&gt;}&lt;br /&gt;public String getAddressStreet1() {&lt;br /&gt;return addressStreet1;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setAddressStreet1 (String addressStreet1) {&lt;br /&gt;this.addressStreet1 =  addressStreet1;&lt;br /&gt;}&lt;br /&gt;public String getAddressStreet2() {&lt;br /&gt;return addressStreet2;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setAddressStreet2 (String addressStreet2) {&lt;br /&gt;this.addressStreet2 =  addressStreet2;&lt;br /&gt;}&lt;br /&gt;public String getCountryCode() {&lt;br /&gt;return countryCode;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setCountryCode (String countryCode) {&lt;br /&gt;this.countryCode =  countryCode;&lt;br /&gt;}&lt;br /&gt;public String getConferenceName() {&lt;br /&gt;return conferenceName;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setConferenceName (String conferenceName) {&lt;br /&gt;this.conferenceName =  conferenceName;&lt;br /&gt;}&lt;br /&gt;public Date getConferenceBeginDate() {&lt;br /&gt;return conferenceBeginDate;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setConferenceBeginDate (Date conferenceBeginDate) {&lt;br /&gt;this.conferenceBeginDate =  conferenceBeginDate;&lt;br /&gt;}&lt;br /&gt;public Date getConferenceEndDate() {&lt;br /&gt;return conferenceEndDate;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setConferenceEndDate (Date conferenceEndDate) {&lt;br /&gt;this.conferenceEndDate =  conferenceEndDate;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Transient&lt;br /&gt;@GET&lt;br /&gt;@Path("{reportId}")&lt;br /&gt;@Produces ({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})&lt;br /&gt;public MyConferenceCoolReport findById (@PathParam ("reportId") Long reportId) {&lt;br /&gt;EntityManager em = XPersistence.getManager();&lt;br /&gt;MyConferenceCoolReport p = em.find(MyConferenceCoolReport.class, reportId);&lt;br /&gt;return p;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Transient&lt;br /&gt;@GET&lt;br /&gt;@QueryParam("{countryCode}")&lt;br /&gt;@Produces ({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})&lt;br /&gt;public MyConfReports find (@QueryParam ("countryCode") String countryCode) {&lt;br /&gt;String q = null;&lt;br /&gt;EntityManager em = XPersistence.getManager();&lt;br /&gt;if (countryCode!=null) {&lt;br /&gt;   q = "select m from MyConferenceCoolReport m where countryCode = '"+countryCode+"'";&lt;br /&gt;} else&lt;br /&gt;q = "select m from MyConferenceCoolReport m ";&lt;br /&gt;Query query = em.createQuery(q);&lt;br /&gt;List&amp;lt;myconferencecoolreport&amp;gt; l = query.getResultList();&lt;br /&gt;MyConfReports m = new MyConfReports();&lt;br /&gt;m.setMyCoolReport(l);&lt;br /&gt;return m;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Annotation of entities&lt;/span&gt;&lt;br /&gt;The previous snippet indicates that entity MyConferenceCoolReport  contains a transient method (findById) use for REST GET operation and using the  param reportId to load an entity. It can be returned either as Xml or in  a Json format.&lt;br /&gt;It contains also a method find that takes a parameter a country code and return a DTO based on the class MyConfReports&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;package my.cool.report.conference.dto.report;&lt;br /&gt;package my.cool.report.conference.dto.report;&lt;br /&gt;&lt;br /&gt;import java.util.*;&lt;br /&gt;&lt;br /&gt;import javax.xml.bind.annotation.*;&lt;br /&gt;&lt;br /&gt;import my.cool.report.conference.domain.report.*;&lt;br /&gt;&lt;br /&gt;@XmlAccessorType(XmlAccessType.FIELD)&lt;br /&gt;@XmlType&lt;br /&gt;@XmlRootElement&lt;br /&gt;public class MyConfReports {&lt;br /&gt;&lt;br /&gt;private List&amp;lt;MyConferenceCoolReport&amp;gt; myCoolReport;&lt;br /&gt;&lt;br /&gt;public MyConfReports () {&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public List&amp;lt;MyConferenceCoolReport&amp;gt; getMyCoolReport() {&lt;br /&gt;return myCoolReport;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setMyCoolReport(List&amp;lt;MyConferenceCoolReport&amp;gt; myCoolReport) {&lt;br /&gt;this.myCoolReport = myCoolReport;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-size:180%;"&gt;Deploy&lt;br /&gt;&lt;/span&gt;Use the ant build on your project.&lt;br /&gt;Remark: do not forget when using openxava with eclipse to set "Build Automatically" on the "Project" tab.&lt;br /&gt;&lt;br /&gt;&lt;jersey-servlet-context&gt;&lt;span style="font-size:180%;"&gt;Testing&lt;br /&gt;&lt;/span&gt;&lt;/jersey-servlet-context&gt;Via the browser type&lt;br /&gt;http://localhost:8080/conference/rest/myreports?countryCode=BE to see all the&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/-2zntMXhYJgY/TnYGxVfJmHI/AAAAAAAAADI/40cVPOi6HL4/s1600/myreports-rest-url-list.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 377px; height: 400px;" src="http://3.bp.blogspot.com/-2zntMXhYJgY/TnYGxVfJmHI/AAAAAAAAADI/40cVPOi6HL4/s400/myreports-rest-url-list.png" alt="" id="BLOGGER_PHOTO_ID_5653713826861389938" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;http://localhost:8080/conference/rest/myreports/&lt;reportid&gt; it returns in an XML format.&lt;br /&gt;&lt;br /&gt;&lt;/reportid&gt;&lt;a href="http://4.bp.blogspot.com/-huNL7FyJ-os/TnX360GdjyI/AAAAAAAAAC4/M1lgItVxfPg/s1600/myreports-rest-url.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 237px;" src="http://4.bp.blogspot.com/-huNL7FyJ-os/TnX360GdjyI/AAAAAAAAAC4/M1lgItVxfPg/s400/myreports-rest-url.png" alt="" id="BLOGGER_PHOTO_ID_5653697497023745826" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;jersey-context&gt;&lt;br /&gt;&lt;br /&gt;&lt;jersey-servlet-context&gt;&lt;span style="font-size:180%;"&gt;Vaadin app client&lt;/span&gt;&lt;br /&gt;//todo&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Conclusion&lt;br /&gt;&lt;/span&gt;//todo&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/jersey-servlet-context&gt;&lt;/jersey-context&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8723196641810122152-6364727596531816353?l=minuteproject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://minuteproject.blogspot.com/feeds/6364727596531816353/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://minuteproject.blogspot.com/2011/09/restication-of-openxava-app-and-vaadin.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/6364727596531816353'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/6364727596531816353'/><link rel='alternate' type='text/html' href='http://minuteproject.blogspot.com/2011/09/restication-of-openxava-app-and-vaadin.html' title='RESTication of Openxava app and Vaadin client'/><author><name>florian</name><uri>http://www.blogger.com/profile/04083442568354390924</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-2zntMXhYJgY/TnYGxVfJmHI/AAAAAAAAADI/40cVPOi6HL4/s72-c/myreports-rest-url-list.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8723196641810122152.post-4854098746349715860</id><published>2011-09-03T22:43:00.000-07:00</published><updated>2012-01-03T05:13:34.122-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><category scheme='http://www.blogger.com/atom/ns#' term='web2'/><category scheme='http://www.blogger.com/atom/ns#' term='liferay'/><category scheme='http://www.blogger.com/atom/ns#' term='openxava'/><category scheme='http://www.blogger.com/atom/ns#' term='rad'/><category scheme='http://www.blogger.com/atom/ns#' term='portlet'/><category scheme='http://www.blogger.com/atom/ns#' term='minuteproject'/><category scheme='http://www.blogger.com/atom/ns#' term='jpa2'/><title type='text'>SQL select to web application in couple of seconds</title><content type='html'>Maybe you are not aware but if you just know how to write one &lt;b&gt;sql select&lt;/b&gt; statement, you're just couple of seconds from having an web application and couple of minutes from enjoying it as a Liferay portlet.&lt;br /&gt;The key ingredients for this recipe are: Openxava, Liferay and ... Minuteproject.&lt;br /&gt;&lt;br /&gt;&lt;u&gt;&lt;b&gt;The equation is:&lt;/b&gt;&lt;/u&gt;&lt;br /&gt;sql select statement (containing one field considered as unique) = Openxava (Webapp) + Liferay (Portlet)&lt;br /&gt;in less than 5 minutes.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;Prerequisites&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Download &lt;a href="http://openxava.org/"&gt;Openxava &lt;/a&gt;(4.2.2), &lt;a href="http://www.liferay.com/"&gt;Liferay&lt;/a&gt;, &lt;a href="http://minuteproject.wikispaces.com/"&gt;Minuteproject &lt;/a&gt;(0.5.7.1+)&lt;/li&gt;&lt;li&gt;Set environment variables OX_HOME and MP_HOME to Openxava and Minuteproject home directories respectively.&lt;/li&gt;&lt;li&gt;Use Java 6&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size: x-large;"&gt;Create your statement&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size: 100%;"&gt;Create a sql select statement&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: 100%;"&gt;Ensure that one of the return field can be considered as &lt;span style="font-weight: bold;"&gt;unique &lt;/span&gt;(if not add one)&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: 100%;"&gt;Create a view from your statement&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size: small;"&gt;&lt;span style="font-size: 100%;"&gt;Ex: CREATE VIEW &lt;b&gt;abc &lt;/b&gt;as&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;Remark:&lt;/span&gt;&lt;br /&gt;Why is it necessary to have a unique field?&lt;br /&gt;It is to ensure that MP can place a @Id JPA2 annotation on one field of the generated entity.&lt;br /&gt;It has to be unique to avoid issue dealing with first level cache.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;Start Minuteproject console&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Point to your model and fill your model name (ex: &lt;b&gt;efg&lt;/b&gt;) &lt;/li&gt;&lt;li&gt;select your view &lt;b&gt;abc &lt;/b&gt;(in customisation tab)&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/li&gt;&lt;li&gt;add the unique field as 'virtual' primary key. Your &lt;span style="font-weight: bold;"&gt;unique &lt;/span&gt;field is not a PK but it will acts as to uniquely identify a record entry.&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/li&gt;&lt;li&gt;Choose target openxava and click generate.&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size: x-large;"&gt;Release your application&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt; go to the generated code&lt;/li&gt;&lt;li&gt;check environment variables (OX_HOME, MP_HOME) are set.&lt;/li&gt;&lt;li&gt;execute from a command prompt: build-&lt;span style="font-weight: bold;"&gt;efg&lt;/span&gt;.cmd/sh&lt;/li&gt;&lt;li&gt;depending on the OS from couple of seconds to a dozen of seconds and a browser should open to the address http://localhost:8080/&lt;span style="font-weight: bold;"&gt;egf&lt;/span&gt;/xava/homeMenu.jsp&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size: x-large;"&gt;Deploy on Liferay&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size: x-large;"&gt; &lt;/span&gt;go to OX_HOME/workspace.dist/&lt;span style="font-weight: bold;"&gt;efg&lt;/span&gt;.dist/&lt;span style="font-weight: bold;"&gt;efg&lt;/span&gt;.war&lt;/li&gt;&lt;li&gt;add &lt;span style="font-weight: bold;"&gt;ejb.jar&lt;/span&gt; and jdbc driver jar in LIFERAY_HOME/tomcat/lib&lt;/li&gt;&lt;li&gt;start Liferay&lt;/li&gt;&lt;li&gt;Upload your portlet&lt;/li&gt;&lt;li&gt;Install your portlet&lt;/li&gt;&lt;li&gt;Enjoy&lt;/li&gt;&lt;/ul&gt;&lt;u&gt;&lt;b&gt;Remark:&lt;/b&gt;&lt;/u&gt;&lt;br /&gt;Whether on the standalone tomcat app or on the Liferay deployed portlet, Openxava is only offering the user selection. It is normal since the DB object is a view, Minuteproject 4 Openxava suppress the Create/Update/Delete, just the Select functionality is kept.&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;span style="font-size: 180%;"&gt;Example&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As model I take the lazuly model project in version 0.1 it contains 13 tables.&lt;br /&gt;The sql to create the schema on mysql can be downloaded at &lt;a href="http://code.google.com/p/lazuly/source/browse/trunk/conference-db/conference-db-mysql-0.1.sql"&gt;http://code.google.com/p/lazuly/source/browse/trunk/conference-db/conference-db-mysql-0.1.sql&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Create your view from your sql select statement&lt;/span&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/-J_ThFrBLFiM/TmOiTq9uIQI/AAAAAAAAACI/iI_dScrBk8o/s1600/create_view_lazuly_my_conference_cool_report.png"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5648536816487112962" src="http://2.bp.blogspot.com/-J_ThFrBLFiM/TmOiTq9uIQI/AAAAAAAAACI/iI_dScrBk8o/s400/create_view_lazuly_my_conference_cool_report.png" style="cursor: pointer; height: 257px; width: 400px;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Start MinuteProject console&lt;/span&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/-kXgatiFEYgk/TmOin1vJg4I/AAAAAAAAACQ/GL4Lp_ztk4o/s1600/MP_console_main_tab_lazuly_mysql_view.png"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5648537162976166786" src="http://2.bp.blogspot.com/-kXgatiFEYgk/TmOin1vJg4I/AAAAAAAAACQ/GL4Lp_ztk4o/s400/MP_console_main_tab_lazuly_mysql_view.png" style="cursor: pointer; height: 409px; width: 404px;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Scope your model&lt;/span&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/-aL6LmMbrZR4/TmPW57D-0CI/AAAAAAAAACg/wrsBSmMhV3c/s1600/MP_console_main_tab_lazuly_mysql_view_scope2.png"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5648594648248012834" src="http://3.bp.blogspot.com/-aL6LmMbrZR4/TmPW57D-0CI/AAAAAAAAACg/wrsBSmMhV3c/s400/MP_console_main_tab_lazuly_mysql_view_scope2.png" style="cursor: pointer; height: 412px; width: 406px;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Generate&lt;/span&gt;&lt;br /&gt;Choose your technology: here Openxava, and click on Generate.&lt;br /&gt;The code will be generated in MP_HOME/output/conference/OpenXava&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Make a standalone Openxava app&lt;/span&gt;&lt;br /&gt;Go to the generated code&lt;br /&gt;Open a prompt&lt;br /&gt;Check or set OX_HOME and MP_HOME&lt;br /&gt;execute build-conference.cmd/sh&lt;br /&gt;Couple of seconds later a browser should open to the model (conference) menu.&lt;br /&gt;Report tab has one entry 'my conference cool report'.&lt;br /&gt;When clicking on it here is a sample screen with data that you could see:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/-cX3jWsuPuDg/TmPbeyTumCI/AAAAAAAAACo/a47l6f-rT_Q/s1600/OX_standalone_report_on_view.png"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5648599679599810594" src="http://3.bp.blogspot.com/-cX3jWsuPuDg/TmPbeyTumCI/AAAAAAAAACo/a47l6f-rT_Q/s400/OX_standalone_report_on_view.png" style="cursor: pointer; height: 240px; width: 420px;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Deploy on Liferay&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Add the datasource (the snippet for tomcat is in OX_HOME/workspace/conference/OpenXava/openxava/other/tomcat/snippet/conference_jndi_for_tomcat_snippet.txt is to be inserted into LIFERAY_HOME/tomcat/conf/context.xml)&lt;/li&gt;&lt;li&gt;Upload the portlet war (OX_HOME/workspace.dist/conference.dist/conference.war&lt;/li&gt;&lt;li&gt;Position it&lt;/li&gt;&lt;li&gt;Enjoy.&lt;/li&gt;&lt;/ul&gt;&lt;a href="http://4.bp.blogspot.com/-6Ta7oRccrmc/TmPe3jDMHRI/AAAAAAAAACw/TPaDKWYeeKM/s1600/LIFERAY_deployed_portlet.png"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5648603403535523090" src="http://4.bp.blogspot.com/-6Ta7oRccrmc/TmPe3jDMHRI/AAAAAAAAACw/TPaDKWYeeKM/s400/LIFERAY_deployed_portlet.png" style="cursor: pointer; height: 249px; width: 431px;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;span style="font-size: 180%;"&gt;Other information&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;You can also find other information regarding Minuteproject 4 Openxava generation at&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://minuteproject.wikispaces.com/OpenXava"&gt;http://minuteproject.wikispaces.com/OpenXava&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://minuteproject.wikispaces.com/OpenXavaSmartRE"&gt;http://minuteproject.wikispaces.com/OpenXavaSmartRE&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://minuteproject.blogspot.com/2011/06/minuteproject-4-openxava-lazuly.html"&gt;http://minuteproject.blogspot.com/2011/06/minuteproject-4-openxava-lazuly.html&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;hr /&gt;&lt;span style="font-size: 180%;"&gt;Conclusion&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size: 100%;"&gt;Your model is your technology tutorial&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: 100%;"&gt;Productivity can be greatly improved&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: 100%;"&gt;Data Quality and troubleshooting operations are quickly available&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: 100%;"&gt;Keep on improving send feed-back to minuteproject@gmail.com or tweet @minuteproject&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8723196641810122152-4854098746349715860?l=minuteproject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://minuteproject.blogspot.com/feeds/4854098746349715860/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://minuteproject.blogspot.com/2011/09/sql-select-to-web-application-in-couple.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/4854098746349715860'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/4854098746349715860'/><link rel='alternate' type='text/html' href='http://minuteproject.blogspot.com/2011/09/sql-select-to-web-application-in-couple.html' title='SQL select to web application in couple of seconds'/><author><name>florian</name><uri>http://www.blogger.com/profile/04083442568354390924</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-J_ThFrBLFiM/TmOiTq9uIQI/AAAAAAAAACI/iI_dScrBk8o/s72-c/create_view_lazuly_my_conference_cool_report.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8723196641810122152.post-7518962034200696359</id><published>2011-08-23T15:09:00.000-07:00</published><updated>2011-08-23T16:06:47.044-07:00</updated><title type='text'>conscious nerd?</title><content type='html'>After all, at the end of the day, what are we geek for?&lt;br /&gt;&lt;br /&gt;Yes folks, we spend hours, days, years of contributing, criticizing, publishing but what is worth for?&lt;br /&gt;What is our mission(s) for those sleepless nights or more pragmatically for this shadow IT? (Yes, we all know that we do ;) )&lt;br /&gt;Is it pride, self sufficience, been the first, be part of the wave or the be the wave itself that drives us?&lt;br /&gt;I do not pretend to introspect nor to find your reason for a free contribution and commitment. I just heap up my own modest contribution to the stack, and wonder where this amont of info will lead us to?&lt;br /&gt;Personally, I think that IT should gently impact our way of living (hey not (only) in the way of booking cheaper holidays...) but in a way to share knowledge and get conscience.&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;Sharing knowledge&lt;/span&gt;: we've been granted by lots of it and we emphasize with our own to grow it bigger and wider.&lt;br /&gt;Promote &lt;span style="font-weight: bold;"&gt;Altruism&lt;/span&gt;: Give the community without expectation!&lt;br /&gt;It may sound naive at first, but it's really a driving force!&lt;br /&gt;You will be remembered! (BTW, The &lt;span style="font-weight: bold;"&gt;long tail&lt;/span&gt; pattern is here for you!)).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Get conscience&lt;/span&gt;: Although our projects, contributions might die or succeed, we are part of an effort that probably transcends us and would lead to a better living and understanding of the position and possibility/feasibilities offered to us.&lt;br /&gt;&lt;span style="font-style: italic;"&gt;By position&lt;/span&gt;, I mean as an actor to the web and community in the present.&lt;br /&gt;&lt;span style="font-style: italic;"&gt;By possibility/feasibility&lt;/span&gt;, I mean the opportunities that will make our destinity brights stronger. Yes IT will lead us to Mars! and the solar system...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Future: is what we decide!&lt;/span&gt; (mitigating the impondarables ;)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8723196641810122152-7518962034200696359?l=minuteproject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://minuteproject.blogspot.com/feeds/7518962034200696359/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://minuteproject.blogspot.com/2011/08/conscious-nerd.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/7518962034200696359'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/7518962034200696359'/><link rel='alternate' type='text/html' href='http://minuteproject.blogspot.com/2011/08/conscious-nerd.html' title='conscious nerd?'/><author><name>florian</name><uri>http://www.blogger.com/profile/04083442568354390924</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8723196641810122152.post-3836387798209963203</id><published>2011-08-06T08:51:00.000-07:00</published><updated>2011-08-23T15:05:46.683-07:00</updated><title type='text'>Project development golden pentagon</title><content type='html'>&lt;span style="font-size:180%;"&gt;Intro&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This article is about the 5 golden principles that lead to success the development of a product.&lt;br /&gt;It also gives pragmatic development tips to streamline the development process.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Golden Pentagon&lt;/span&gt;&lt;br /&gt;The 5 major objectives that any software project should fulfill are to deliver a solution that&lt;br /&gt;&lt;ul&gt;&lt;li style="color: rgb(51, 51, 255);"&gt;matches business requirements&lt;/li&gt;&lt;li style="color: rgb(51, 51, 255);"&gt;is operationable&lt;/li&gt;&lt;li style="color: rgb(51, 51, 255);"&gt;is within budget&lt;/li&gt;&lt;li style="color: rgb(51, 51, 255);"&gt;is within scheduled timeframe&lt;/li&gt;&lt;li style="color: rgb(51, 51, 255);"&gt;is maintable&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:130%;"&gt;Match Business Requirements&lt;/span&gt;&lt;br /&gt;Been out of scope is obviously useless. So the closest the better. But which methodology to use???&lt;br /&gt;The IT world is full of acronyms and methodology all in one solution but what I recommand is the following:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;AVOID RUP!!!&lt;/li&gt;&lt;/ul&gt;It brings nothing except troubles and an ironical conclusion: if it fails it means that you did not follow the methodology correctly.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;CHOOSE AGILE&lt;/li&gt;&lt;/ul&gt;But here again the goal is to produce something and not to be lost within scrums, sprints, backlogs and burndown curves.&lt;br /&gt;So how to concretely describe the business requirements in order fulfill the product owner desires? And how to make those requirement be in line with the Truth (the stuff that will run in production)?&lt;br /&gt;&lt;ul&gt;&lt;li&gt;CHOOSE FITNESSE&lt;/li&gt;&lt;/ul&gt;Write stories to describe your business requirements make and exhaustive list of them. Reach the developement contract accord between project owner, developers, analysts, tester, project manager. Since is wiki human readable it is feasible.&lt;br /&gt;Write the correct fixtures to loosely couple your business requirements with the underlying code.&lt;br /&gt;This will bodyguard your development effort with Quality Assurance.&lt;br /&gt;Meanwhile to put that in place there is some learning curve and some fixture development time effort. To easy this part MP provides some ready to use fixtures.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Minuteproject asset:&lt;/span&gt;&lt;br /&gt;When working with a Datamodel, MP generates an entire wiki with associated fixtures to make crud operation easy.&lt;br /&gt;Example :&lt;br /&gt;&lt;ul&gt;&lt;li&gt;you need to illustrate a scenario, in the set up use MP fixtures to reset and populate the database.&lt;/li&gt;&lt;li&gt;after couple of features performing a suite of UCs you need to have a sanity check in the database (to check the data is correctly stored). MP generates the Fitnesse fixture for the desired sanity check query materialized in a DB object view.&lt;/li&gt;&lt;/ul&gt;A specific entry for the MP 'Lazuly' showcase will be put in this blog soon. Stay tuned.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Be operationable&lt;/span&gt;&lt;br /&gt;What's the point to develop something that runs properly. This is a wide concept be in the terms of web development is to have a solution that scales properly, does not be to be restarted (no memory leaks), sustain concurrency and responds fast.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Stay within budget&lt;/span&gt;&lt;br /&gt;Also obvious and speaking from itself, it is a reality that most project forget and tend to  counterbalance by betting on CR (Change request), i.e. anappropiate analysis leading to clumsy UCs raise profitable CRs.&lt;br /&gt;When the analysis tackles with model (Change/enhancement), MP is ready to cope with it with extrem performance (just a couple of seconds) to have your backend aline/online.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Stay within deadlines&lt;/span&gt;&lt;br /&gt;What is the interest of releasing after deadlines (or what is the interest of setting dealines if we know from the start there're just virtual?????).&lt;br /&gt;By remove a huge dev burden, MP helps you handle deadline easily. From to 40% to 60% of your developement effort can be handle by MP according the tracks you use.&lt;br /&gt;Write less code.&lt;br /&gt;WRITE ONLY THE CODE YOU NEED.&lt;br /&gt;Do not overcode.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Think future: stay maintable&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;//this slot is under construction, wait a while for it to be finished... there are some many things to say!!!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8723196641810122152-3836387798209963203?l=minuteproject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://minuteproject.blogspot.com/feeds/3836387798209963203/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://minuteproject.blogspot.com/2011/08/project-development-golden-pentagon.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/3836387798209963203'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/3836387798209963203'/><link rel='alternate' type='text/html' href='http://minuteproject.blogspot.com/2011/08/project-development-golden-pentagon.html' title='Project development golden pentagon'/><author><name>florian</name><uri>http://www.blogger.com/profile/04083442568354390924</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8723196641810122152.post-4916762592432473647</id><published>2011-07-19T13:19:00.000-07:00</published><updated>2011-07-19T15:07:41.094-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vaadin'/><category scheme='http://www.blogger.com/atom/ns#' term='openxava'/><category scheme='http://www.blogger.com/atom/ns#' term='minuteproject'/><title type='text'>3 features I would dream to see in Openxava</title><content type='html'>&lt;span style="font-size:180%;"&gt;Pull BI out of the ghetto&lt;/span&gt;&lt;br /&gt;Currently 'all in one' framework such as grails, playframework, openxava, roo, rails behave all more or less the same for CRUD modal navigation&lt;br /&gt;Start from a list (resulting from a search screen or default filtering), then goes on one entity to manipulate.&lt;br /&gt;Personally, I think there is/should be a step before. I would like to see the big picture instead of scrolling down a list or ajusting search params.&lt;br /&gt;Furthermore, this overview can be express in format of a graphical chart which has a greater expressing power than looking at records.&lt;br /&gt;&lt;br /&gt;To give a concrete example:&lt;br /&gt;I design a 'helpdesk app' and one entity is called 'issue'. Issue entity has a number of fields among those 'type', 'status', 'origin', 'date-creation', 'date-resolution'.&lt;br /&gt;Would'nt it be nice to visualize:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;on a piechart the ventilation by type/status or/and origin, and then click on one portion to get the result filtered accordingly;&lt;/li&gt;&lt;li&gt;on a trend chart the evolution of the issue by  type/status or/and origin against 'date-creation', 'date-resolution' before drilling down into the entries.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Those information come from BI queries that should be added to ease navigation and clarify the business. I found more attractive to come from a dashboard representing an overview of the business than being stick to the detail in an early phase.&lt;br /&gt;It would bridge the gap between the BI world an the 'attached-entity' centric paradigm.&lt;br /&gt;&lt;br /&gt;For Openxava, we could easily imagine other annotation&lt;br /&gt;&lt;br /&gt;@dashboards&lt;br /&gt;@dashboard (representation="piechart", filtering="type,status,origin")&lt;br /&gt;@dashboard (representation="trend", filtering="type,status,origin", start-period="date", period-sample='day/month/year', time-param="date-creation)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Content search&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Framework search as compass or hibernate-search propose some content search solution based on annotations.&lt;br /&gt;If we use compass we can imagine that entity tagged as @searchableRoot could have a free text search for the field marked as @searchable.&lt;br /&gt;&lt;span style="font-size:180%;"&gt;&lt;br /&gt;GWT - ideally Vaadin rendering&lt;/span&gt;&lt;br /&gt;It speaks from itself.&lt;br /&gt;Get the benefit of other community for front-end snippets.&lt;br /&gt;Integration with GAE, google maps...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;And minuteproject in all that&lt;/span&gt;&lt;br /&gt;Well, all that is marked as annotation could be described as model enrichment when it is data centric.&lt;br /&gt;So we could easily imagine to have a field enrichment stating that it belongs to a dashboard, or better have a global convention that applies to the model that states that all fields ending with type or status are part of a dashboard. In this case one line of configuration is needed to impact the entire navigation model.&lt;br /&gt;The same is true for content search but here the enrichment is already available for minuteproject4Solr track.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8723196641810122152-4916762592432473647?l=minuteproject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://minuteproject.blogspot.com/feeds/4916762592432473647/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://minuteproject.blogspot.com/2011/07/3-features-i-would-dream-to-see-in.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/4916762592432473647'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/4916762592432473647'/><link rel='alternate' type='text/html' href='http://minuteproject.blogspot.com/2011/07/3-features-i-would-dream-to-see-in.html' title='3 features I would dream to see in Openxava'/><author><name>florian</name><uri>http://www.blogger.com/profile/04083442568354390924</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8723196641810122152.post-718195772081866150</id><published>2011-07-11T01:53:00.000-07:00</published><updated>2011-07-15T15:57:18.223-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rad'/><category scheme='http://www.blogger.com/atom/ns#' term='minuteproject'/><category scheme='http://www.blogger.com/atom/ns#' term='jpa2'/><category scheme='http://www.blogger.com/atom/ns#' term='reverse-engineering'/><title type='text'>JPA2 simple reverse-engineering via MP console</title><content type='html'>This article shows how quickly you can reverse-engineering for JPA2 via minuteproject console.&lt;br /&gt;&lt;br /&gt;The console is just find to have a quick look at what you can expect.&lt;br /&gt;&lt;br /&gt;The console has two &lt;span style="font-weight: bold;"&gt;catalogs&lt;/span&gt;:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;One for the target DB (for the moment there are 4 of them Oracle, DB2, mysql, hsqldb)&lt;/li&gt;&lt;li&gt;One for the target technologies (there are couples such as JPA2, spring/hibernate/Jpa/DAO, grails, playframework, vaadin).&lt;/li&gt;&lt;/ul&gt;The &lt;span style="font-weight: bold;"&gt;DB catalog&lt;/span&gt; holds for each db parameters corresponding to its default configurations such as:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;primary key (Oracle use sequence, Mysql autoincrement)&lt;/li&gt;&lt;li&gt;dialect (for hibernate or orm vendor specific)&lt;/li&gt;&lt;li&gt;jdbc driver class&lt;br /&gt;&lt;/li&gt;&lt;li&gt;maven driver artifacts&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;To add new DB just add some nodes in /catalog/database-catalog.xml and restart the console.&lt;br /&gt;You can share your new configuration for DB with &lt;a href="mailto:minuteproject@gmail.com"&gt;minuteproject&lt;/a&gt; to be included in the next release.&lt;br /&gt;&lt;br /&gt;The &lt;span style="font-weight: bold;"&gt;technology catalog&lt;/span&gt; holds for each track the set of artifacts for the different level (field, entity, package, model, application) that is to be generated.&lt;br /&gt;&lt;br /&gt;Here a little video illustrating how to use the console:&lt;br /&gt;&lt;br /&gt;&lt;iframe src="http://player.vimeo.com/video/26222049?title=0&amp;amp;byline=0&amp;amp;portrait=0" frameborder="0" height="300" width="400"&gt;&lt;/iframe&gt;&lt;p&gt;&lt;a href="http://vimeo.com/26222049"&gt;MinuteProject 4 JPA2: reverse-engineering via console&lt;/a&gt; from &lt;a href="http://vimeo.com/user7520466"&gt;minuteproject&lt;/a&gt; on &lt;a href="http://vimeo.com/"&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;If you want additional feature you have to use Minuteproject with a configuration file.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8723196641810122152-718195772081866150?l=minuteproject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://minuteproject.blogspot.com/feeds/718195772081866150/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://minuteproject.blogspot.com/2011/07/minuteproject-console-jpa2-simple.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/718195772081866150'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/718195772081866150'/><link rel='alternate' type='text/html' href='http://minuteproject.blogspot.com/2011/07/minuteproject-console-jpa2-simple.html' title='JPA2 simple reverse-engineering via MP console'/><author><name>florian</name><uri>http://www.blogger.com/profile/04083442568354390924</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8723196641810122152.post-1781689148802280586</id><published>2011-06-27T05:14:00.001-07:00</published><updated>2011-07-15T16:26:27.369-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='querydsl'/><category scheme='http://www.blogger.com/atom/ns#' term='rad'/><category scheme='http://www.blogger.com/atom/ns#' term='minuteproject'/><category scheme='http://www.blogger.com/atom/ns#' term='jpa2'/><category scheme='http://www.blogger.com/atom/ns#' term='reverse-engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>MinuteProject 4 JPA2: Lazuly showcase</title><content type='html'>&lt;span style="color: rgb(0, 0, 0);font-size:180%;"&gt;Intro&lt;/span&gt;&lt;br /&gt;The goal of this article is to have a working JPA2 layer on top of a data model by writting 0 (&lt;span style="font-weight: bold;"&gt;yes ZERO&lt;/span&gt;) lines of code.&lt;br /&gt;Lazuly-db is a opensource database hosted on googlecode that represents the structure of a database holding conference related informations.&lt;br /&gt;Lazuly-db will be used as a showcase of various MinuteProject technology tracks.&lt;br /&gt;In version 0.1 it has 13 tables, 2 views.&lt;br /&gt;&lt;br /&gt;This article explains the different steps to quickly have a working JPA2 backend.&lt;br /&gt;It is furthermore a tutorial on how to enrich the database model to get customized artifacts providing specific behaviour.&lt;br /&gt;The purpose is to give to user enough material to customize it and go on extending your model.&lt;br /&gt;&lt;span style="font-size:180%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);font-size:180%;"&gt;MinuteProject short story&lt;/span&gt;&lt;br /&gt;The idea behind &lt;a href="http://minuteproject.wikispaces.com/"&gt;minuteproject&lt;/a&gt; is to&lt;br /&gt;&lt;ul&gt;&lt;li&gt;go fast;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;reduce the technology learning curve by knowledge cristalization;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;improve the quality of the artifact;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;shorten drastically the time to market of the product.&lt;/li&gt;&lt;/ul&gt;Minuteproject acts as a Productivity provider targeting multiple aspects of the reverse-engineering for a target architecture (here JPA2).&lt;br /&gt;While most of existing reverse-engineering solution focus on one part of your architecture (Domain Object), MinuteProject can generate artifacts related to:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;columns;&lt;/li&gt;&lt;li&gt;entities (tables,views);&lt;br /&gt;&lt;/li&gt;&lt;li&gt;stored procedures;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;package;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;model;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;application.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;It allows the developer to achieve 'reproductability' that is a great complement of reusability.&lt;br /&gt;Reusability allows to bundle common behavior into a package/framework/specification in order to use them but not to code them.&lt;br /&gt;Reproductability allows to reach the same quality of artifacts (config/classes...) matching a target architecture (reused) although the context changes (DB model).&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);font-size:180%;"&gt;JPA2 track&lt;/span&gt;&lt;br /&gt;JPA2 is a JEE specification for persisting objects in a database.&lt;br /&gt;MinuteProject 4 JPA2 (release 0.5.5) offers a reverse-engineering solution targeting JPA2 artifacts:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Java Entity classes for tables and views;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;JPA2 metamodel;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;persistence xml;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;maven pom.xml;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;vendor specific implementation;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;querydsl integration.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;More information can be found at &lt;a href="http://minuteproject.wikispaces.com/JPA2"&gt;minuteproject4jpa2&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);font-size:180%;"&gt;Operating principle&lt;/span&gt;&lt;br /&gt;MinuteProject works with a configuration file.&lt;br /&gt;This file holds the information regarding the model and how to enrich it. It also specifies the target bundle of templates for a technology track.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Datasource&lt;/span&gt;&lt;br /&gt;Lazuly DB main entities: The schema below resumes the lazuly DB main entities (tables/views) and theirs relationships.&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/-awt3HOPzbr0/TgiGheT2ARI/AAAAAAAAAAo/0sjSL2dFVFs/s1600/lazuly-0.1001.jpg"&gt;&lt;br /&gt;&lt;/a&gt;&lt;a href="http://4.bp.blogspot.com/-a_2AdwjlJt8/TgiHbjvTzwI/AAAAAAAAAAw/VWSHCX5O6cU/s1600/lazuly-0.1-entities.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 283px;" src="http://4.bp.blogspot.com/-a_2AdwjlJt8/TgiHbjvTzwI/AAAAAAAAAAw/VWSHCX5O6cU/s400/lazuly-0.1-entities.bmp" alt="" id="BLOGGER_PHOTO_ID_5622893042291953410" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;This part summarizes the different configurations used:&lt;br /&gt;&lt;br /&gt;Here is the sample xml configuration that is applied to the model&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;!DOCTYPE root&amp;gt;&lt;br /&gt;&amp;lt;generator-config&amp;gt;&lt;br /&gt;&amp;lt;configuration&amp;gt;&lt;br /&gt;&amp;lt;model name="conference" version="1.0" package-root="net.sf.mp.demo"&amp;gt;&lt;br /&gt;&amp;lt;!-- &amp;lt;model name="lazuly" version="1.0" package-root="mp.demo"&amp;gt; --&amp;gt;&lt;br /&gt;&amp;lt;data-model&amp;gt;&lt;br /&gt;&amp;lt;driver name="mysql" version="5.1.16" groupId="mysql"&lt;br /&gt;artifactId="mysql-connector-java"&amp;gt;&amp;lt;/driver&amp;gt;&lt;br /&gt;&amp;lt;dataSource&amp;gt;&lt;br /&gt;&amp;lt;driverClassName&amp;gt;org.gjt.mm.mysql.Driver&amp;lt;/driverClassName&amp;gt;&lt;br /&gt;&amp;lt;url&amp;gt;jdbc:mysql://127.0.0.1:3306/conference&amp;lt;/url&amp;gt;&lt;br /&gt;&amp;lt;username&amp;gt;root&amp;lt;/username&amp;gt;&lt;br /&gt;&amp;lt;password&amp;gt;mysql&amp;lt;/password&amp;gt;&lt;br /&gt;&amp;lt;/dataSource&amp;gt;&lt;br /&gt;&amp;lt;!-- for Oracle and DB2 please set the schema &amp;lt;schema&amp;gt; &amp;lt;/schema&amp;gt; --&amp;gt;&lt;br /&gt;&amp;lt;primaryKeyPolicy oneGlobal="true"&amp;gt;&lt;br /&gt;&amp;lt;primaryKeyPolicyPattern name="autoincrementPattern"&amp;gt;&amp;lt;/primaryKeyPolicyPattern&amp;gt;&lt;br /&gt;&amp;lt;/primaryKeyPolicy&amp;gt;&lt;br /&gt;&amp;lt;/data-model&amp;gt;&lt;br /&gt;&amp;lt;business-model&amp;gt;&lt;br /&gt;&amp;lt;!-- &amp;lt;generation-condition&amp;gt; &amp;lt;condition type="exclude" startsWith="DUAL"&amp;gt;&amp;lt;/condition&amp;gt;&lt;br /&gt;&amp;lt;/generation-condition&amp;gt; --&amp;gt;&lt;br /&gt;&amp;lt;business-package default="conference"&amp;gt;&lt;br /&gt;&amp;lt;condition type="package" startsWith="STAT" result="statistics"&amp;gt;&amp;lt;/condition&amp;gt;&lt;br /&gt;&amp;lt;condition type="package" startsWith="COUNTRY" result="admin"&amp;gt;&amp;lt;/condition&amp;gt;&lt;br /&gt;&amp;lt;condition type="package" startsWith="ROLE" result="admin"&amp;gt;&amp;lt;/condition&amp;gt;&lt;br /&gt;&amp;lt;/business-package&amp;gt;&lt;br /&gt;&amp;lt;enrichment&amp;gt;&lt;br /&gt;&amp;lt;conventions&amp;gt;&lt;br /&gt;&amp;lt;column-naming-convention type="apply-strip-column-name-suffix"&lt;br /&gt;pattern-to-strip="_ID" /&amp;gt;&lt;br /&gt;&amp;lt;reference-naming-convention&lt;br /&gt;type="apply-referenced-alias-when-no-ambiguity" is-to-plurialize="true" /&amp;gt;&lt;br /&gt;&amp;lt;/conventions&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;entity name="PRESENTATION"&amp;gt;&lt;br /&gt;&amp;lt;field name="STATUS"&amp;gt;&lt;br /&gt;&amp;lt;property tag="checkconstraint" alias="presentation_status"&amp;gt;&lt;br /&gt;&amp;lt;property name="PROPOSAL" value="PROPOSAL" /&amp;gt;&lt;br /&gt;&amp;lt;property name="ACTIVE" value="ACTIVE" /&amp;gt;&lt;br /&gt;&amp;lt;/property&amp;gt;&lt;br /&gt;&amp;lt;/field&amp;gt;&lt;br /&gt;&amp;lt;/entity&amp;gt;&lt;br /&gt;&amp;lt;entity name="SPONSOR"&amp;gt;&lt;br /&gt;&amp;lt;field name="STATUS"&amp;gt;&lt;br /&gt;&amp;lt;property tag="checkconstraint" alias="sponsor_status"&amp;gt;&lt;br /&gt;&amp;lt;property name="PENDING" value="PENDING" /&amp;gt;&lt;br /&gt;&amp;lt;property name="ACTIVE" value="ACTIVE" /&amp;gt;&lt;br /&gt;&amp;lt;/property&amp;gt;&lt;br /&gt;&amp;lt;/field&amp;gt;&lt;br /&gt;&amp;lt;field name="PRIVILEGE_TYPE"&amp;gt;&lt;br /&gt;&amp;lt;property tag="checkconstraint" alias="sponsor_privilege"&amp;gt;&lt;br /&gt;&amp;lt;property name="GOLDEN" value="Golden" /&amp;gt;&lt;br /&gt;&amp;lt;property name="SILVER" value="Silver" /&amp;gt;&lt;br /&gt;&amp;lt;property name="BRONZE" value="Bronze" /&amp;gt;&lt;br /&gt;&amp;lt;/property&amp;gt;&lt;br /&gt;&amp;lt;/field&amp;gt;&lt;br /&gt;&amp;lt;/entity&amp;gt;&lt;br /&gt;&amp;lt;!-- views --&amp;gt;&lt;br /&gt;&amp;lt;entity name="stat_mb_per_ctry_conf" alias="MEMBER_PER_COUNTRY_AND_CONFERENCE"&amp;gt;&lt;br /&gt;&amp;lt;virtual-primary-key isRealPrimaryKey="true"&amp;gt;&lt;br /&gt;&amp;lt;property name="virtualPrimaryKey" value="ID" /&amp;gt;&lt;br /&gt;&amp;lt;/virtual-primary-key&amp;gt;&lt;br /&gt;&amp;lt;/entity&amp;gt;&lt;br /&gt;&amp;lt;entity name="stat_mb_by_role" alias="MEMBER_PER_ROLE_COUNTRY_AND_CONFERENCE"&amp;gt;&lt;br /&gt;&amp;lt;virtual-primary-key isRealPrimaryKey="true"&amp;gt;&lt;br /&gt;&amp;lt;property name="virtualPrimaryKey" value="id" /&amp;gt;&lt;br /&gt;&amp;lt;/virtual-primary-key&amp;gt;&lt;br /&gt;&amp;lt;field name="stat_mb_per_ctry_conf_ID" linkToTargetEntity="stat_mb_per_ctry_conf"&lt;br /&gt;linkToTargetField="id"&amp;gt;&amp;lt;/field&amp;gt;&lt;br /&gt;&amp;lt;/entity&amp;gt;&lt;br /&gt;&amp;lt;/enrichment&amp;gt;&lt;br /&gt;&amp;lt;/business-model&amp;gt;&lt;br /&gt;&amp;lt;/model&amp;gt;&lt;br /&gt;&amp;lt;targets&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;target refname="JPA2" fileName="mp-template-config-JPA2.xml"&lt;br /&gt;outputdir-root="../../dev/output/JPA2" templatedir-root="../../template/framework/jpa"&amp;gt;&lt;br /&gt;&amp;lt;property name="add-querydsl" value="2.1.2"&amp;gt;&amp;lt;/property&amp;gt;&lt;br /&gt;&amp;lt;property name="add-jpa2-implementation" value="hibernate"&amp;gt;&amp;lt;/property&amp;gt;&lt;br /&gt;&amp;lt;/target&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;target refname="LIB" fileName="mp-template-config-bsla-LIB-features.xml"&lt;br /&gt;templatedir-root="../../template/framework/bsla"&amp;gt;&lt;br /&gt;&amp;lt;/target&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/targets&amp;gt;&lt;br /&gt;&amp;lt;/configuration&amp;gt;&lt;br /&gt;&amp;lt;/generator-config&amp;gt;&lt;br /&gt;&lt;/pre&gt;The configuration provides:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A model name: conference, version and package root;&lt;/li&gt;&lt;li&gt;the driver as maven reference;&lt;/li&gt;&lt;li&gt;connection parameters;&lt;/li&gt;&lt;li&gt;primarykey policy (autoincrement)&lt;/li&gt;&lt;li&gt;business packages: entities starting with stat go to 'statistics'...;role, countries goes in administration package&lt;/li&gt;&lt;li&gt;convention: strip-column-name-suffix _ID (by convention in the database, I have column naming ending with '_ID' for foreign key. Here the Java naming convention can defer from the DB naming&lt;/li&gt;&lt;li&gt;convention: &lt;span&gt;&lt;span class="attribute-value"&gt;apply-referenced-alias-when-no-ambiguity indicating that when a table has a one2many relationship with other (i.e. has child), if it has not 2 children with the same other side table (no ambiguity) than the name of the variable is based on the other side table, and &lt;/span&gt;&lt;/span&gt;plurialized (english) collections&lt;/li&gt;&lt;li&gt;&lt;span&gt;&lt;span class="attribute-value"&gt;Entity enrichment: name alias (can have a distinct Java class name than the one derived from the DB);&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;&lt;span class="attribute-value"&gt;Field enrichment: provide a check constraint that becomes a Java Enum&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;&lt;span class="attribute-value"&gt;Entity (views) enrichment by providing them a primary key (create a unique key) by adding foreignkey.&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;The target part of the configuration specifies against which target technology, MinuteProject has to generate. Here the track is JPA2, where  it is specified to use querydsl 2.1.2 and a JPA vendor implementation Hibernate.&lt;br /&gt;Those indications are used to generate pom.xml and persistence.xml files.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);font-size:180%;"&gt;Sources and installation&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Lazuly project&lt;/span&gt;&lt;br /&gt;Svn the source as describe on &lt;a href="http://code.google.com/p/lazuly/source/checkout"&gt;http://code.google.com/p/lazuly/source/checkout&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Mysql&lt;/span&gt;&lt;br /&gt;Install mysql&lt;br /&gt;run &lt;a href="http://lazuly.googlecode.com/svn/trunk/conference-db/conference-db-mysql-0.1.sql"&gt;conference-db.0.1.sql&lt;/a&gt; on schema conference&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Minuteproject&lt;/span&gt;&lt;br /&gt;Download and install &lt;a href="http://sourceforge.net/projects/minuteproject/files/"&gt;minuteproject&lt;/a&gt; 0.5.5 or higher. Minuteproject is installed in MP_HOME.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Execution&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Copy the file&lt;/span&gt;&lt;a href="http://code.google.com/p/lazuly/source/browse/trunk/lazuly-jpa2/mp-config-CONFERENCE-JPA2.xml"&gt;&lt;/a&gt; &lt;a href="http://lazuly.googlecode.com/svn/trunk/lazuly-jpa2/mp-config-CONFERENCE-JPA2.xml"&gt;http://lazuly.googlecode.com/svn/trunk/lazuly-jpa2/mp-config-CONFERENCE-JPA2.xml&lt;/a&gt; &lt;span style="font-weight: bold;"&gt;into &lt;/span&gt;%MP_HOME%/mywork/config&lt;/li&gt;&lt;li&gt;Adapt the connection parameters in mp-config-CONFERENCE-JPA2.xml&lt;/li&gt;&lt;li&gt;from a command line execute: generate-model.(sh/cmd) mp-config-CONFERENCE-JPA2.xml&lt;/li&gt;&lt;/ul&gt;Normally within couple of seconds (1 to 5) the code should be generated (If DB instance and minuteproject run is on same machine)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Alternate execution&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Open minuteproject console %MP_HOME%/bin/start-console.(cmd/sh)&lt;/li&gt;&lt;li&gt;field the connection parameters&lt;/li&gt;&lt;li&gt;add package root and model name&lt;br /&gt;&lt;/li&gt;&lt;li&gt;click generate&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;This alternative generation works fine to give a first glance at what you can have as output. A better enrichment is available via the xml config as previously described.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);font-size:180%;"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;Output&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;The output can be browsed at &lt;a href="http://code.google.com/p/lazuly/source/browse/#svn%2Ftrunk%2Flazuly-jpa2"&gt;http://code.google.com/p/lazuly/source/browse/#svn%2Ftrunk%2Flazuly-jpa2&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Here are some samples of what has been generated in terms of&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 0, 0);"&gt;Structure&lt;/span&gt;&lt;br /&gt;Here the structure open with as an eclipse-maven project&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/--vTjeKw4qo0/TgmIiII8CGI/AAAAAAAAABI/oqNwI6ROsd0/s1600/conferenceBackEnd-JPA2-lazuly-0.1-all.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 214px; height: 400px;" src="http://4.bp.blogspot.com/--vTjeKw4qo0/TgmIiII8CGI/AAAAAAAAABI/oqNwI6ROsd0/s400/conferenceBackEnd-JPA2-lazuly-0.1-all.bmp" alt="" id="BLOGGER_PHOTO_ID_5623175729630677090" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Java class as JPA2 entity with enumeration&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;, OneToMany, ManyToOne, ManyToMany&lt;/span&gt;&lt;br /&gt;You can note that the field 'abstract' in the table 'presentation' is converted to 'abstractName' to avoid compilation error. This is true for all the java reserved keywords. The getter and setter are adapted accordingly.&lt;br /&gt;&lt;pre name="code" class="java"&gt;package net.sf.mp.demo.conference.conference;&lt;br /&gt;&lt;br /&gt;import java.sql.*;&lt;br /&gt;import java.util.Date;&lt;br /&gt;import java.util.List;&lt;br /&gt;import java.util.ArrayList;&lt;br /&gt;import java.util.Set;&lt;br /&gt;import java.util.HashSet;&lt;br /&gt;&lt;br /&gt;import javax.persistence.*;&lt;br /&gt;&lt;br /&gt;import net.sf.mp.demo.conference.conference.Evaluation;&lt;br /&gt;import net.sf.mp.demo.conference.conference.PresentationPlace;&lt;br /&gt;import net.sf.mp.demo.conference.conference.Speaker;&lt;br /&gt;import net.sf.mp.demo.conference.enumeration.conference.PresentationStatusEnum;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;*&lt;br /&gt;* &amp;lt;p&amp;gt;Title: Presentation&amp;lt;/p&amp;gt;&lt;br /&gt;*&lt;br /&gt;* &amp;lt;p&amp;gt;Description: Domain Object describing a Presentation entity&amp;lt;/p&amp;gt;&lt;br /&gt;*&lt;br /&gt;*/&lt;br /&gt;@Entity (name="Presentation")&lt;br /&gt;@Table (name="presentation")&lt;br /&gt;public class Presentation {&lt;br /&gt;&lt;br /&gt;@Id @Column(name="id" )&lt;br /&gt;@GeneratedValue(strategy = GenerationType.AUTO)&lt;br /&gt;private Long id;&lt;br /&gt;&lt;br /&gt;@Column(name="start_time",   nullable=false,  unique=false)&lt;br /&gt;private Timestamp startTime;&lt;br /&gt;@Column(name="end_time",   nullable=false,  unique=false)&lt;br /&gt;private Timestamp endTime;&lt;br /&gt;@Column(name="abstract",  length=500, nullable=false,  unique=false)&lt;br /&gt;private String abstractName;&lt;br /&gt;@Column(name="title",  length=255, nullable=false,  unique=false)&lt;br /&gt;private String title;&lt;br /&gt;@Enumerated (EnumType.STRING)&lt;br /&gt;private PresentationStatusEnum status;&lt;br /&gt;@Column(name="proposal_time",    nullable=true,  unique=false)&lt;br /&gt;private Timestamp proposalTime;&lt;br /&gt;&lt;br /&gt;@ManyToOne (fetch=FetchType.LAZY )&lt;br /&gt;@JoinColumn(name="presentation_place_id", referencedColumnName = "id",  nullable=true,  unique=false )&lt;br /&gt;private PresentationPlace presentationPlaceId;&lt;br /&gt;&lt;br /&gt;@OneToMany (targetEntity=net.sf.mp.demo.conference.conference.Evaluation.class, fetch=FetchType.LAZY, mappedBy="presentationId", cascade=CascadeType.REMOVE)//, cascade=CascadeType.ALL)&lt;br /&gt;private Set &amp;lt;Evaluation&amp;gt; evaluations = new HashSet&amp;lt;Evaluation&amp;gt;();&lt;br /&gt;&lt;br /&gt;@ManyToMany&lt;br /&gt;@JoinTable(name="SPEAKER_PRESENTATION",&lt;br /&gt;joinColumns=@JoinColumn(name="presentation_id"),&lt;br /&gt;inverseJoinColumns=@JoinColumn(name="speaker_id")&lt;br /&gt;)&lt;br /&gt;private Set &amp;lt;Speaker&amp;gt; speakers = new HashSet &amp;lt;Speaker&amp;gt; ();&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Default constructor&lt;br /&gt;*/&lt;br /&gt;public Presentation() {&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public Long getId() {&lt;br /&gt;return id;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setId (Long id) {&lt;br /&gt;this.id =  id;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public Timestamp getStartTime() {&lt;br /&gt;return startTime;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setStartTime (Timestamp startTime) {&lt;br /&gt;this.startTime =  startTime;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public Timestamp getEndTime() {&lt;br /&gt;return endTime;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setEndTime (Timestamp endTime) {&lt;br /&gt;this.endTime =  endTime;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public String getAbstractName() {&lt;br /&gt;return abstractName;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setAbstractName (String abstractName) {&lt;br /&gt;this.abstractName =  abstractName;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public String getTitle() {&lt;br /&gt;return title;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setTitle (String title) {&lt;br /&gt;this.title =  title;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public PresentationStatusEnum getStatus() {&lt;br /&gt;return status;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setStatus (PresentationStatusEnum status) {&lt;br /&gt;this.status =  status;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public Timestamp getProposalTime() {&lt;br /&gt;return proposalTime;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setProposalTime (Timestamp proposalTime) {&lt;br /&gt;this.proposalTime =  proposalTime;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public PresentationPlace getPresentationPlaceId () {&lt;br /&gt;return presentationPlaceId;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setPresentationPlaceId (PresentationPlace presentationPlaceId) {&lt;br /&gt;this.presentationPlaceId = presentationPlaceId;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public Set&amp;lt;Evaluation&amp;gt; getEvaluations() {&lt;br /&gt;if (evaluations == null){&lt;br /&gt;evaluations = new HashSet&amp;lt;Evaluation&amp;gt;();&lt;br /&gt;}&lt;br /&gt;return evaluations;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setEvaluations (Set&amp;lt;Evaluation&amp;gt; evaluations) {&lt;br /&gt;this.evaluations = evaluations;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void addEvaluations (Evaluation evaluation) {&lt;br /&gt;getEvaluations().add(evaluation);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public Set&amp;lt;Speaker&amp;gt; getSpeakers() {&lt;br /&gt;if (speakers == null){&lt;br /&gt;speakers = new HashSet&amp;lt;Speaker&amp;gt;();&lt;br /&gt;}&lt;br /&gt;return speakers;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setSpeakers (Set&amp;lt;Speaker&amp;gt; speakers) {&lt;br /&gt;this.speakers = speakers;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void addSpeakers (Speaker speakers) {&lt;br /&gt;getSpeakers().add(speakers);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight: bold;"&gt;Enumeration&lt;/span&gt;&lt;br /&gt;You can note the 'equals (string s)' method which is quite handy.&lt;br /&gt;&lt;pre name="code" class="java"&gt;package net.sf.mp.demo.conference.enumeration.conference;&lt;br /&gt;&lt;br /&gt;import java.util.ArrayList;&lt;br /&gt;import java.util.List;&lt;br /&gt;&lt;br /&gt;public enum SponsorPrivilegeTypeEnum {&lt;br /&gt;&lt;br /&gt;GOLDEN("Golden"),&lt;br /&gt;SILVER("Silver"),&lt;br /&gt;BRONZE("Bronze");&lt;br /&gt;&lt;br /&gt;private final String value;&lt;br /&gt;&lt;br /&gt;SponsorPrivilegeTypeEnum(String v) {&lt;br /&gt;value = v;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public String value() {&lt;br /&gt;return value;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public static SponsorPrivilegeTypeEnum fromValue(String v) {&lt;br /&gt;for (SponsorPrivilegeTypeEnum c : SponsorPrivilegeTypeEnum.values()) {&lt;br /&gt;if (c.value.equals(v)) {&lt;br /&gt;return c;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;return null;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Return a list that contains all the enumeration values&lt;br /&gt;* @return List&amp;lt;SponsorPrivilegeTypeEnum&amp;gt; the that contains all the enumeration values&lt;br /&gt;*/&lt;br /&gt;public static List&amp;lt;SponsorPrivilegeTypeEnum&amp;gt; getList() {&lt;br /&gt;List&amp;lt;SponsorPrivilegeTypeEnum&amp;gt; list = new ArrayList&amp;lt;SponsorPrivilegeTypeEnum&amp;gt;();&lt;br /&gt;for (SponsorPrivilegeTypeEnum c : SponsorPrivilegeTypeEnum.values()) {&lt;br /&gt;list.add(c);&lt;br /&gt;}&lt;br /&gt;return list;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* @param value&lt;br /&gt;* @return boolean : true if the value exist in the enum&lt;br /&gt;*/&lt;br /&gt;public static boolean contains (String value) {&lt;br /&gt;for (SponsorPrivilegeTypeEnum c : SponsorPrivilegeTypeEnum.values()) {&lt;br /&gt;if (c.toString().equals(value))&lt;br /&gt;return true;&lt;br /&gt;}&lt;br /&gt;return false;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public static boolean containsValue (String value) {&lt;br /&gt;for (SponsorPrivilegeTypeEnum c : SponsorPrivilegeTypeEnum.values()) {&lt;br /&gt;if (c.value().equals(value))&lt;br /&gt;return true;&lt;br /&gt;}&lt;br /&gt;return false;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public boolean equals (String s) {&lt;br /&gt;if (s==null) return false;&lt;br /&gt;return s.equals(value);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight: bold; color: rgb(0, 0, 0);"&gt;Java class as JPA2 entity for view&lt;/span&gt;&lt;br /&gt;You can note the enrichment performed is translated into different Java and DB naming conventions for the entity itself as well as its dependencies.&lt;br /&gt;Now you can use the view for all the JPA2 select operations.&lt;br /&gt;&lt;pre name="code" class="java"&gt;package net.sf.mp.demo.conference.statistics;&lt;br /&gt;&lt;br /&gt;import java.sql.*;&lt;br /&gt;import java.util.Date;&lt;br /&gt;import java.util.List;&lt;br /&gt;import java.util.ArrayList;&lt;br /&gt;import java.util.Set;&lt;br /&gt;import java.util.HashSet;&lt;br /&gt;&lt;br /&gt;import javax.persistence.*;&lt;br /&gt;&lt;br /&gt;import net.sf.mp.demo.conference.statistics.MemberPerRoleCountryAndConference;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;*&lt;br /&gt;* &amp;lt;p&amp;gt;Title: MemberPerCountryAndConference&amp;lt;/p&amp;gt;&lt;br /&gt;*&lt;br /&gt;* &amp;lt;p&amp;gt;Description: Domain Object describing a MemberPerCountryAndConference entity&amp;lt;/p&amp;gt;&lt;br /&gt;*&lt;br /&gt;*/&lt;br /&gt;@Entity (name="MemberPerCountryAndConference")&lt;br /&gt;@Table (name="stat_mb_per_ctry_conf")&lt;br /&gt;public class MemberPerCountryAndConference {&lt;br /&gt;&lt;br /&gt;@Id @Column(name="id" ,length=300)&lt;br /&gt;private String id;&lt;br /&gt;&lt;br /&gt;@Column(name="country",  length=45, nullable=false,  unique=false)&lt;br /&gt;private String country;&lt;br /&gt;@Column(name="conference_name",  length=255, nullable=false,  unique=false)&lt;br /&gt;private String conferenceName;&lt;br /&gt;@Column(name="number",   nullable=false,  unique=false)&lt;br /&gt;private Long number;&lt;br /&gt;&lt;br /&gt;@OneToMany (targetEntity=net.sf.mp.demo.conference.statistics.MemberPerRoleCountryAndConference.class, fetch=FetchType.LAZY, mappedBy="statMbPerCtryConfId", cascade=CascadeType.REMOVE)//, cascade=CascadeType.ALL)&lt;br /&gt;private Set &amp;lt;MemberPerRoleCountryAndConference&amp;gt; memberPerRoleCountryAndConferences = new HashSet&amp;lt;MemberPerRoleCountryAndConference&amp;gt;();&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Default constructor&lt;br /&gt;*/&lt;br /&gt;public MemberPerCountryAndConference() {&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public String getId() {&lt;br /&gt;return id;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setId (String id) {&lt;br /&gt;this.id =  id;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public String getCountry() {&lt;br /&gt;return country;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setCountry (String country) {&lt;br /&gt;this.country =  country;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public String getConferenceName() {&lt;br /&gt;return conferenceName;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setConferenceName (String conferenceName) {&lt;br /&gt;this.conferenceName =  conferenceName;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public Long getNumber() {&lt;br /&gt;return number;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setNumber (Long number) {&lt;br /&gt;this.number =  number;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public Set&amp;lt;MemberPerRoleCountryAndConference&amp;gt; getMemberPerRoleCountryAndConferences() {&lt;br /&gt;if (memberPerRoleCountryAndConferences == null){&lt;br /&gt;memberPerRoleCountryAndConferences = new HashSet&amp;lt;MemberPerRoleCountryAndConference&amp;gt;();&lt;br /&gt;}&lt;br /&gt;return memberPerRoleCountryAndConferences;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setMemberPerRoleCountryAndConferences (Set&amp;lt;MemberPerRoleCountryAndConference&amp;gt; memberPerRoleCountryAndConferences) {&lt;br /&gt;this.memberPerRoleCountryAndConferences = memberPerRoleCountryAndConferences;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void addMemberPerRoleCountryAndConferences (MemberPerRoleCountryAndConference memberPerRoleCountryAndConference) {&lt;br /&gt;getMemberPerRoleCountryAndConferences().add(memberPerRoleCountryAndConference);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;span style="color: rgb(0, 0, 0);font-size:180%;"&gt;Run&lt;/span&gt;&lt;br /&gt;Since it generate a pom.xml, download maven and run 'mvn install'&lt;br /&gt;It generates the lazuly backend jar containing the entities, the metamodel and the querydsl classes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8723196641810122152-1781689148802280586?l=minuteproject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://minuteproject.blogspot.com/feeds/1781689148802280586/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://minuteproject.blogspot.com/2011/06/minuteproject-4-jpa2-lazuly-showcase.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/1781689148802280586'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/1781689148802280586'/><link rel='alternate' type='text/html' href='http://minuteproject.blogspot.com/2011/06/minuteproject-4-jpa2-lazuly-showcase.html' title='MinuteProject 4 JPA2: Lazuly showcase'/><author><name>florian</name><uri>http://www.blogger.com/profile/04083442568354390924</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-a_2AdwjlJt8/TgiHbjvTzwI/AAAAAAAAAAw/VWSHCX5O6cU/s72-c/lazuly-0.1-entities.bmp' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8723196641810122152.post-2669351772785958179</id><published>2011-06-27T05:12:00.000-07:00</published><updated>2011-12-15T07:01:44.274-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='liferay'/><category scheme='http://www.blogger.com/atom/ns#' term='openxava'/><category scheme='http://www.blogger.com/atom/ns#' term='rad'/><category scheme='http://www.blogger.com/atom/ns#' term='portlet'/><category scheme='http://www.blogger.com/atom/ns#' term='minuteproject'/><category scheme='http://www.blogger.com/atom/ns#' term='reverse-engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='tomcat'/><title type='text'>MinuteProject 4 Openxava: Lazuly showcase</title><content type='html'>&lt;span style="color: black; font-size: 180%;"&gt;Intro&lt;/span&gt;&lt;br /&gt;The goal of this article is to have a working Openxava on top of a data model by writting 0 (&lt;span style="font-weight: bold;"&gt;yes ZERO&lt;/span&gt;) lines of code. This application has to run as a standalone webapp or as portlets in a portal.&lt;br /&gt;&lt;div&gt;The model used is the Lazuly-db which is a opensource database hosted on googlecode that represents the structure of a database holding conference related informations.&lt;br /&gt;Lazuly-db will be used as a showcase of various MinuteProject technology tracks.&lt;br /&gt;In version 0.1 it has 13 tables, 2 views.&lt;br /&gt;&lt;br /&gt;This article explains the different steps to quickly have a create an Openxava application.&lt;br /&gt;It is furthermore a tutorial on how to enrich the database model to get customized Openxava artifacts providing specific behaviour.&lt;br /&gt;The purpose is to give to user enough material to customize it and go on extending your model.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you want to see the result quickly, I encourage you to see the &lt;span style="font-weight: bold;"&gt;videos&lt;/span&gt; (downwards on this page).&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;span style="color: black; font-size: 180%;"&gt;OpenXava&lt;/span&gt;&lt;br /&gt;Is an opensource product that makes CRUD RIA modal application in a very quick way.&lt;br /&gt;It enforces the DRY principle with a comprehensive set of annotations.&lt;/div&gt;&lt;div&gt;Openxava is a generic framework that dynamically generates the presentation layer based on custom annotation.&lt;br /&gt;&lt;br /&gt;MinuteProject 4 Openxava offers a reverse-engineering solution targeting OX architecture.&lt;/div&gt;&lt;div&gt;Here are the set of artifacts MinuteProject will generate:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;JPA2 and OpenXava annotated entities;&lt;/li&gt;&lt;li&gt;associated metamodel;&lt;/li&gt;&lt;li&gt;drop down list artifacts for enumeration;&lt;/li&gt;&lt;li&gt;Navigation menu;&lt;/li&gt;&lt;li&gt;build script (windows and unix);&lt;/li&gt;&lt;li&gt;tomcat datasouce configuration snippet and context.xml;&lt;/li&gt;&lt;li&gt;internationalisation.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="color: black; font-size: 180%;"&gt;Operating principle&lt;/span&gt;&lt;/div&gt;&lt;div&gt;MinuteProject works with a configuration file.&lt;br /&gt;This file holds the information regarding the model and how to enrich it. It also specifies the target bundle of templates for a technology track (here Openxava).&lt;br /&gt;&lt;br /&gt;&lt;span style="color: black; font-size: 130%;"&gt;Datasource&lt;/span&gt;&lt;br /&gt;Lazuly DB main entities: The schema below resumes the lazuly DB main entities (tables/views) and theirs relationships.&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/-awt3HOPzbr0/TgiGheT2ARI/AAAAAAAAAAo/0sjSL2dFVFs/s1600/lazuly-0.1001.jpg"&gt;&lt;br /&gt;&lt;/a&gt;&lt;a href="http://4.bp.blogspot.com/-a_2AdwjlJt8/TgiHbjvTzwI/AAAAAAAAAAw/VWSHCX5O6cU/s1600/lazuly-0.1-entities.bmp"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5622893042291953410" src="http://4.bp.blogspot.com/-a_2AdwjlJt8/TgiHbjvTzwI/AAAAAAAAAAw/VWSHCX5O6cU/s400/lazuly-0.1-entities.bmp" style="cursor: pointer; display: block; height: 283px; margin-bottom: 10px; margin-left: auto; margin-right: auto; margin-top: 0px; text-align: center; width: 400px;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="color: black; font-size: 130%;"&gt;Configuration&lt;/span&gt;&lt;/div&gt;&lt;div&gt;This part summarizes the different configurations used:&lt;br /&gt;&lt;br /&gt;&lt;pre class="xml" name="code"&gt;&amp;lt;!DOCTYPE root&amp;gt;&lt;br /&gt;&amp;lt;generator-config&amp;gt;&lt;br /&gt;&amp;lt;configuration&amp;gt;&lt;br /&gt;&amp;lt;model name="conference" version="1.0" package-root="net.sf.mp.demo"&amp;gt;&lt;br /&gt;&amp;lt;data-model&amp;gt;&lt;br /&gt;&amp;lt;driver name="mysql" version="5.1.16" groupId="mysql" artifactId="mysql-connector-java"&amp;gt;&amp;lt;/driver&amp;gt;&lt;br /&gt;&amp;lt;dataSource&amp;gt;&lt;br /&gt;&amp;lt;driverClassName&amp;gt;org.gjt.mm.mysql.Driver&amp;lt;/driverClassName&amp;gt;&lt;br /&gt;&amp;lt;url&amp;gt;jdbc:mysql://127.0.0.1:3306/conference&amp;lt;/url&amp;gt;&lt;br /&gt;&amp;lt;username&amp;gt;&amp;lt;/username&amp;gt;&lt;br /&gt;&amp;lt;password&amp;gt;&amp;lt;/password&amp;gt;&lt;br /&gt;&amp;lt;/dataSource&amp;gt;&lt;br /&gt;&amp;lt;!--&lt;br /&gt;for Oracle and DB2 please set the schema &amp;lt;schema&amp;gt; &amp;lt;/schema&amp;gt;&lt;br /&gt;--&amp;gt;&lt;br /&gt;&amp;lt;primaryKeyPolicy oneGlobal="true"&amp;gt;&lt;br /&gt;&amp;lt;primaryKeyPolicyPattern name="autoincrementPattern"&amp;gt;&amp;lt;/primaryKeyPolicyPattern&amp;gt;&lt;br /&gt;&amp;lt;/primaryKeyPolicy&amp;gt;&lt;br /&gt;&amp;lt;/data-model&amp;gt;&lt;br /&gt;&amp;lt;business-model&amp;gt;&lt;br /&gt;&amp;lt;!--&lt;br /&gt;&amp;lt;generation-condition&amp;gt; &amp;lt;condition type="exclude"&lt;br /&gt;startsWith="DUAL"&amp;gt;&amp;lt;/condition&amp;gt; &amp;lt;/generation-condition&amp;gt;&lt;br /&gt;--&amp;gt;&lt;br /&gt;&amp;lt;business-package default="conference"&amp;gt;&lt;br /&gt;&amp;lt;condition type="package" startsWith="STAT" result="statistics"&amp;gt;&amp;lt;/condition&amp;gt;&lt;br /&gt;&amp;lt;condition type="package" startsWith="COUNTRY" result="admin"&amp;gt;&amp;lt;/condition&amp;gt;&lt;br /&gt;&amp;lt;condition type="package" startsWith="ROLE" result="admin"&amp;gt;&amp;lt;/condition&amp;gt;&lt;br /&gt;&amp;lt;/business-package&amp;gt;&lt;br /&gt;&amp;lt;enrichment&amp;gt;&lt;br /&gt;&amp;lt;conventions&amp;gt;&lt;br /&gt;&amp;lt;column-naming-convention type="apply-strip-column-name-suffix"&lt;br /&gt;pattern-to-strip="_ID" /&amp;gt;&lt;br /&gt;&amp;lt;reference-naming-convention&lt;br /&gt;type="apply-referenced-alias-when-no-ambiguity" is-to-plurialize="true" /&amp;gt;&lt;br /&gt;&amp;lt;/conventions&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;entity name="COUNTRY" content-type="reference-data"&amp;gt;&lt;br /&gt;&amp;lt;semantic-reference&amp;gt;&lt;br /&gt;&amp;lt;sql-path path="NAME" /&amp;gt;&lt;br /&gt;&amp;lt;/semantic-reference&amp;gt;&lt;br /&gt;&amp;lt;/entity&amp;gt;&lt;br /&gt;&amp;lt;entity name="CONFERENCE_MEMBER"&amp;gt;&lt;br /&gt;&amp;lt;semantic-reference&amp;gt;&lt;br /&gt;&amp;lt;sql-path path="FIRST_NAME" /&amp;gt;&lt;br /&gt;&amp;lt;sql-path path="LAST_NAME" /&amp;gt;&lt;br /&gt;&amp;lt;/semantic-reference&amp;gt;&lt;br /&gt;&amp;lt;field name="STATUS"&amp;gt;&lt;br /&gt;&amp;lt;property tag="checkconstraint" alias="conference_member_status"&amp;gt;&lt;br /&gt;&amp;lt;property name="PENDING" value="PENDING" /&amp;gt;&lt;br /&gt;&amp;lt;property name="ACTIVE" value="ACTIVE" /&amp;gt;&lt;br /&gt;&amp;lt;/property&amp;gt;&lt;br /&gt;&amp;lt;/field&amp;gt;&lt;br /&gt;&amp;lt;field name="EMAIL"&amp;gt;&lt;br /&gt;&amp;lt;stereotype stereotype="EMAIL" /&amp;gt;&lt;br /&gt;&amp;lt;/field&amp;gt;&lt;br /&gt;&amp;lt;/entity&amp;gt;&lt;br /&gt;&amp;lt;entity name="SPEAKER"&amp;gt;&lt;br /&gt;&amp;lt;field name="BIO"&amp;gt;&lt;br /&gt;&amp;lt;stereotype stereotype="HTML_TEXT" /&amp;gt;&lt;br /&gt;&amp;lt;/field&amp;gt;&lt;br /&gt;&amp;lt;field name="PHOTO"&amp;gt;&lt;br /&gt;&amp;lt;stereotype stereotype="PHOTO" /&amp;gt;&lt;br /&gt;&amp;lt;/field&amp;gt;&lt;br /&gt;&amp;lt;field name="WEB_SITE_URL"&amp;gt;&lt;br /&gt;&amp;lt;stereotype stereotype="WEBURL" /&amp;gt;&lt;br /&gt;&amp;lt;/field&amp;gt;&lt;br /&gt;&amp;lt;/entity&amp;gt;&lt;br /&gt;&amp;lt;entity name="PRESENTATION"&amp;gt;&lt;br /&gt;&amp;lt;field name="STATUS"&amp;gt;&lt;br /&gt;&amp;lt;property tag="checkconstraint" alias="presentation_status"&amp;gt;&lt;br /&gt;&amp;lt;property name="PROPOSAL" value="PROPOSAL" /&amp;gt;&lt;br /&gt;&amp;lt;property name="ACTIVE" value="ACTIVE" /&amp;gt;&lt;br /&gt;&amp;lt;/property&amp;gt;&lt;br /&gt;&amp;lt;/field&amp;gt;&lt;br /&gt;&amp;lt;/entity&amp;gt;&lt;br /&gt;&amp;lt;entity name="SPONSOR"&amp;gt;&lt;br /&gt;&amp;lt;field name="STATUS"&amp;gt;&lt;br /&gt;&amp;lt;property tag="checkconstraint" alias="sponsor_status"&amp;gt;&lt;br /&gt;&amp;lt;property name="PENDING" value="PENDING" /&amp;gt;&lt;br /&gt;&amp;lt;property name="ACTIVE" value="ACTIVE" /&amp;gt;&lt;br /&gt;&amp;lt;/property&amp;gt;&lt;br /&gt;&amp;lt;/field&amp;gt;&lt;br /&gt;&amp;lt;field name="PRIVILEGE_TYPE"&amp;gt;&lt;br /&gt;&amp;lt;property tag="checkconstraint" alias="sponsor_privilege"&amp;gt;&lt;br /&gt;&amp;lt;property name="GOLDEN" value="Golden" /&amp;gt;&lt;br /&gt;&amp;lt;property name="SILVER" value="Silver" /&amp;gt;&lt;br /&gt;&amp;lt;property name="BRONZE" value="Bronze" /&amp;gt;&lt;br /&gt;&amp;lt;/property&amp;gt;&lt;br /&gt;&amp;lt;/field&amp;gt;&lt;br /&gt;&amp;lt;/entity&amp;gt;&lt;br /&gt;&amp;lt;!-- views --&amp;gt;&lt;br /&gt;&amp;lt;entity name="stat_mb_per_ctry_conf" alias="MEMBER_PER_COUNTRY_AND_CONFERENCE"&amp;gt;&lt;br /&gt;&amp;lt;virtual-primary-key isRealPrimaryKey="true"&amp;gt;&lt;br /&gt;&amp;lt;property name="virtualPrimaryKey" value="ID" /&amp;gt;&lt;br /&gt;&amp;lt;/virtual-primary-key&amp;gt;&lt;br /&gt;&amp;lt;/entity&amp;gt;&lt;br /&gt;&amp;lt;entity name="stat_mb_by_role" alias="MEMBER_PER_ROLE_COUNTRY_AND_CONFERENCE"&amp;gt;&lt;br /&gt;&amp;lt;virtual-primary-key isRealPrimaryKey="true"&amp;gt;&lt;br /&gt;&amp;lt;property name="virtualPrimaryKey" value="id" /&amp;gt;&lt;br /&gt;&amp;lt;/virtual-primary-key&amp;gt;&lt;br /&gt;&amp;lt;field name="stat_mb_per_ctry_conf_ID" linkToTargetEntity="stat_mb_per_ctry_conf"&lt;br /&gt;linkToTargetField="id"&amp;gt;&amp;lt;/field&amp;gt;&lt;br /&gt;&amp;lt;/entity&amp;gt;&lt;br /&gt;&amp;lt;/enrichment&amp;gt;&lt;br /&gt;&amp;lt;/business-model&amp;gt;&lt;br /&gt;&amp;lt;/model&amp;gt;&lt;br /&gt;&amp;lt;targets&amp;gt;&lt;br /&gt;&amp;lt;!-- openxava --&amp;gt;&lt;br /&gt;&amp;lt;target refname="OpenXava" name="OpenXava"&lt;br /&gt;fileName="mp-template-config-openxava-last-features.xml"&lt;br /&gt;outputdir-root="../../DEV/output/openxava/conference"&lt;br /&gt;templatedir-root="../../template/framework/openxava"&amp;gt;&lt;br /&gt;&amp;lt;/target&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;target refname="JPA2-LIB" fileName="mp-template-config-JPA2-LIB.xml"&lt;br /&gt;templatedir-root="../../template/framework/jpa"&amp;gt;&lt;br /&gt;&amp;lt;/target&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;target refname="BSLA-LIB" fileName="mp-template-config-bsla-LIB-features.xml"&lt;br /&gt;templatedir-root="../../template/framework/bsla"&amp;gt;&lt;br /&gt;&amp;lt;/target&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/targets&amp;gt;&lt;br /&gt;&amp;lt;/configuration&amp;gt;&lt;br /&gt;&amp;lt;/generator-config&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;span style="color: black; font-size: 130%;"&gt;&lt;span style="font-size: small;"&gt;This version works for MP version 0.5.x&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black; font-size: 130%;"&gt;&lt;span style="font-size: small;"&gt;For version above 0.6 add&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre class="xml" name="code"&gt;&lt;br /&gt;   &amp;lt;target refname="CACHE-LIB" &lt;br /&gt;      fileName="mp-template-config-CACHE-LIB.xml" &lt;br /&gt;      templatedir-root="../../template/framework/cache"&amp;gt;&lt;br /&gt;   &amp;lt;/target&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;span style="color: black; font-size: 130%;"&gt;&lt;span style="font-size: small;"&gt;&amp;nbsp;&lt;/span&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="color: black; font-size: 130%;"&gt;Configuration explained&lt;/span&gt;&lt;/div&gt;If you have read the &lt;a href="http://minuteproject.blogspot.com/2011/06/minuteproject-4-jpa2-lazuly-showcase.html"&gt;minuteproject 4 JPA2 lazuly showcase article&lt;/a&gt; on this blog, you would notice that the configuration is similar to the one for JPA2 track. It is the case for everything regarding the model location (same model) and the enrichment, meanwhile it defers regarding the target, since it uses OpenXava.&lt;br /&gt;&lt;br /&gt;The configuration provides:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A model name: conference, version and package root;&lt;/li&gt;&lt;li&gt;the driver as maven reference;&lt;/li&gt;&lt;li&gt;connection parameters;&lt;/li&gt;&lt;li&gt;primarykey policy (autoincrement)&lt;/li&gt;&lt;li&gt;business packages: entities starting with stat go to 'statistics'...;role, countries goes in administration package. Those will be converted into distinct menu tabs.&lt;/li&gt;&lt;li&gt;convention: strip-column-name-suffix _ID (by convention in the database, I have column naming ending with '_ID' for foreign key. Here the Java naming convention can defer from the DB naming&lt;/li&gt;&lt;li&gt;convention: &lt;span class="attribute-value"&gt;apply-referenced-alias-when-no-ambiguity indicating that when a table has a one2many relationship with other (i.e. has child), if it has not 2 children with the same other side table (no ambiguity) than the name of the variable is based on the other side table, and &lt;/span&gt;plurialized (english) collections&lt;/li&gt;&lt;li&gt;&lt;span class="attribute-value"&gt;Entity enrichment: name alias (can have a distinct Java class name than the one derived from the DB);&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="attribute-value"&gt;Field enrichment: provide a check constraint that becomes an Openxava drop down list&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="attribute-value"&gt;Entity (views) enrichment by providing them a primary key (create a unique key) by adding foreignkey. In this way we can have an alternative navigation model on top of some BI views.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="attribute-value"&gt;Tag field content-type="reference-data" apply to ROLE and COUNTRY entry will trigger the following navigation behavior: you cannot navigation from a role entry to children CONFERENCE_MEMBER in the application, but form &lt;/span&gt;CONFERENCE_MEMBER you can associate roles.&lt;/li&gt;&lt;li&gt;stereotype="EMAIL" will be converted in its associated email stereotype on Openxava triggering email format validation, same for WEB_SITE_URL&lt;/li&gt;&lt;li&gt;stereotype="HTML_TEXT" applied to SPEAKER.BIO field will be converted in its associated html_text stereotype on Openxava offering a Rich text format facility&lt;/li&gt;&lt;li&gt;stereotype="PHOTO" applied to SPEAKER.PHOTO field will be converted in file upload facility by Openxava&lt;/li&gt;&lt;/ul&gt;Additional information on how to enrich the model can be found at &lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://minuteproject.wikispaces.com/OpenXava"&gt;http://minuteproject.wikispaces.com/OpenXava&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://minuteproject.wikispaces.com/OpenXavaSmartRE"&gt;http://minuteproject.wikispaces.com/OpenXavaSmartRE&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="color: black; font-size: 180%;"&gt;Sources and installation&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black; font-size: 130%;"&gt;Lazuly project&lt;/span&gt;&lt;br /&gt;Svn the source as describe on &lt;a href="http://code.google.com/p/lazuly/source/checkout"&gt;http://code.google.com/p/lazuly/source/checkout&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: black; font-size: 130%;"&gt;Mysql&lt;/span&gt;&lt;br /&gt;Install mysql&lt;br /&gt;run &lt;a href="http://lazuly.googlecode.com/svn/trunk/conference-db/conference-db-mysql-0.1.sql"&gt;conference-db.0.1.sql&lt;/a&gt; on schema conference&lt;br /&gt;&lt;br /&gt;&lt;span style="color: black; font-size: 130%;"&gt;Minuteproject&lt;/span&gt;&lt;br /&gt;Download and install &lt;a href="http://sourceforge.net/projects/minuteproject/files/"&gt;minuteproject&lt;/a&gt; 0.5.5. Minuteproject is installed in MP_HOME.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="color: black; font-size: 130%;"&gt;Openxava&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Download and install openxava &lt;span style="font-weight: bold;"&gt;4.1.2.&lt;/span&gt; Openxava is installed in OX_HOME.&lt;br /&gt;&lt;span style="font-size: 85%;"&gt;&lt;span style="font-family: arial; font-weight: bold;"&gt;Remark&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: arial;"&gt;This demo is based on OX 4.1.2, if you are using a more recent version there may not be foreward compatibility. Release (MP 0.5.6 will be compliant with OX 4.2.1). In fact there is one artifact generated home.jsp that is based on OX module.jsp. If this artifact changes between OX release, there is potentially an error.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="color: black; font-size: 180%;"&gt;Generation&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Copy the file&lt;/span&gt; &lt;a href="http://code.google.com/p/lazuly/source/browse/trunk/lazuly-openxava/mp-config-LAZULY-OPENXAVA.xml"&gt;http://code.google.com/p/lazuly/source/browse/trunk/lazuly-openxava/mp-config-LAZULY-OPENXAVA.xml&lt;/a&gt; &lt;span style="font-weight: bold;"&gt;into &lt;/span&gt;%MP_HOME%/mywork/config&lt;/li&gt;&lt;li&gt;Adapt the connection parameters in mp-config-LAZULY-OPENXAVA.xml&lt;/li&gt;&lt;li&gt;from a command line execute: generate-model.(sh/cmd) mp-config-LAZULY-OPENXAVA.xml&lt;/li&gt;&lt;/ul&gt;The resulting generated code goes to %MP_HOME%/DEV/output/openxava/conference&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;span style="color: black; font-size: 180%;"&gt;Structure of the Openxava project&lt;/span&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;Here the structure open with as an eclipse project in the openxava workspace&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://2.bp.blogspot.com/-DUAxiDJMpc4/TiDQiE6PizI/AAAAAAAAABY/l9d64o3gOZg/s1600/openxava-lazuly-code-generated.png"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5629728818065279794" src="http://2.bp.blogspot.com/-DUAxiDJMpc4/TiDQiE6PizI/AAAAAAAAABY/l9d64o3gOZg/s400/openxava-lazuly-code-generated.png" style="cursor: pointer; height: 400px; width: 206px;" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="color: black; font-size: 180%;"&gt;Execution&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;check mysql.jar is in tomcat/lib&lt;/li&gt;&lt;li&gt;check that the system variables: ox_home, mp_home are set to Openxava and MinuteProject installation directories.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;Open a prompt on /DEV/output/openxava/conference, and execute build-conference.cmd.&lt;/div&gt;&lt;div&gt;It will&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Create an Openxava project&lt;/li&gt;&lt;li&gt;Build openxava web app&lt;/li&gt;&lt;li&gt;Build openxava portlets (to be deployed on a portal such as Liferay)&lt;/li&gt;&lt;li&gt;Copy context.xml (take care that it overwrite the existing one)&lt;/li&gt;&lt;li&gt;Start tomcat&lt;/li&gt;&lt;li&gt;Deploy the application&lt;/li&gt;&lt;li&gt;Start you default browser to the Conference Home menu.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;The enjoy the navigation.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="color: black; font-size: 180%;"&gt;Videos&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;Video starting from scratch to deployed application&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;iframe frameborder="0" height="300" src="http://player.vimeo.com/video/26493208?title=0&amp;amp;byline=0&amp;amp;portrait=0" width="400"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;br /&gt;Video of the resulting application&lt;br /&gt;&lt;br /&gt;&lt;iframe frameborder="0" height="300" src="http://player.vimeo.com/video/26552354?title=0&amp;amp;byline=0&amp;amp;portrait=0" width="400"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8723196641810122152-2669351772785958179?l=minuteproject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://minuteproject.blogspot.com/feeds/2669351772785958179/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://minuteproject.blogspot.com/2011/06/minuteproject-4-openxava-lazuly.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/2669351772785958179'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/2669351772785958179'/><link rel='alternate' type='text/html' href='http://minuteproject.blogspot.com/2011/06/minuteproject-4-openxava-lazuly.html' title='MinuteProject 4 Openxava: Lazuly showcase'/><author><name>florian</name><uri>http://www.blogger.com/profile/04083442568354390924</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-a_2AdwjlJt8/TgiHbjvTzwI/AAAAAAAAAAw/VWSHCX5O6cU/s72-c/lazuly-0.1-entities.bmp' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8723196641810122152.post-17159684103497380</id><published>2009-11-01T06:56:00.000-08:00</published><updated>2009-12-23T07:00:08.329-08:00</updated><title type='text'></title><content type='html'>&lt;span style="font-size:100%;"&gt;MinuteProject 0.4 Release&lt;/span&gt; &lt;a href="https://sourceforge.net/projects/minuteproject/files/"&gt;download&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;MinuteProject 0.4 release contains the following generation capabilities&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Generation for persistence layers (hibernate, JPA, iBatis)&lt;/li&gt;&lt;li&gt;Generation for Spring configuration files&lt;/li&gt;&lt;li&gt;Generation for Fitnesse&lt;/li&gt;&lt;/ul&gt;It allows the user to create full stack DAO backend with advanced CRUD functionalities.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;It also provides a quick way to perform BDD (Behavior Driven Development) with FitNesse when working with a Database:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Generate FitNesse Wiki Snippets to integrate in your Business Scenario Pages&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Generate FitNesse Fixture classes to brigde integrate your CRUD snippet with your Database.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8723196641810122152-17159684103497380?l=minuteproject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://minuteproject.blogspot.com/feeds/17159684103497380/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://minuteproject.blogspot.com/2009/11/minuteproject-0.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/17159684103497380'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8723196641810122152/posts/default/17159684103497380'/><link rel='alternate' type='text/html' href='http://minuteproject.blogspot.com/2009/11/minuteproject-0.html' title=''/><author><name>florian</name><uri>http://www.blogger.com/profile/04083442568354390924</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry></feed>
