Showing posts with label statement driven development. Show all posts
Showing posts with label statement driven development. Show all posts

Friday, August 23, 2013

SDD as a productivity weapon 4 openxava

Under construction (need 0.8.5 for generation) but can be used in the meantime as a OX tutorial to work with any jdbc sql statement (here stored-procedure)

Productivity challenge

With SDD (Statement driven development) what is important is I/O and functionality.
The model is secondary.
To experience it, let's have a store procedure that perform a required operation and get a web application out of it with Minuteproject 4 Openxava.

Mission statement

UC general statement

You have information to pass to a DB via a web application to perform a function.
You would like the input to be validated base on type, presence, stereotype, membership.

UC specific

You need a functionality to ask for role in the application.
As input you pass 3 params:
  • username
  • email
  • requested role
 UserName is:
  • mandatory
  • string
Email is:
  • mandatory
  • stereotype (format)
 Request role is:
  • mandatory
  • should be one of the application specific role

The function shall also:
  • register the time of creation
  • status=TO_TREAT
The function is provided in format of a stored procedure.

Dev environment constraints

A schema containing
  • a table SEC_ROLE containing roles
  • a table BUS_USER_ROLE_REQUEST
  • a store procedure ASK_FOR_ROLE
  • CREATE PROCEDURE ask_for_role(
      IN username VARCHAR(255),
      IN email VARCHAR(255),
       IN role VARCHAR(255)
    )
    BEGIN
    Insert into BUS_USER_ROLE_REQUEST (USERNAME, EMAIL, ROLE_REQUESTED, STATUS, REQUEST_DATE)
    values (username, email, role, 'TO_TREAT', NOW());
    
    END
    
  • SEC_ROLE and  BUS_USER_ROLE_REQUEST are not linked by any relationships (no FK nor m2m).

Configuration

This configuration focus on the SDD part
<!DOCTYPE root>
<generator-config>
 <configuration>
        <conventions>
            <target-convention type="enable-updatable-code-feature" />
        </conventions>

<!-- other configuration, data-model where sec_role and bus_user_role_request are present... -->

  <model name="porphyry" version="1.0" package-root="net.sf.mp.demo">
   <statement-model>
    <queries>
            <query name="ask_for_role" id="ask_for_role" >
                         <query-body>
                         <value>
<![CDATA[call ask_for_role (?,?,?)]]>
                            </value>
                         </query-body>
                         <query-params>
                             <query-param name="username" is-mandatory="true" type="string" sample="'a'" is-id="true"></query-param>
                             <query-param name="email" is-mandatory="true" type="string" sample="'b'">
                              <stereotype stereotype="EMAIL" />
                             </query-param>
                             <query-param name="role" is-mandatory="true" type="string" sample="'c'">
                                <query-param-link entity-name="sec_role" field-name="role"/>
                             </query-param>
                         </query-params>
                     </query>
                </queries>
            </statement-model>
         </model>
  <targets catalog-entry="OpenXava" >
  </targets>
 </configuration>
</generator-config> 
The main points are:
  • call ask_for_role with 3 parameters
  • description of the parameters (name, type, presence, stereotype)
  • restrict to a set of value coming from a table and field (query-param-link)

Openxava design flow

The input is in format of an Openxava/JPA2 entity to enable binding and link to other entity.
But this entity will never be persisted and never lookup.
The input screen will be accessed directly, and button match the action. After the action is performed a message is display.
To enable this flow OX controllers.xml and application.xml nodes are generated.
The action binding the input data from the form; validating and calling the store procedure call are also generated.

Generated code

Input/Output bean generated


import javax.persistence.*;
import org.openxava.annotations.*;

import net.sf.mp.demo.porphyry.domain.security.Role;

@Entity (name="AskForRoleIn")
@Table (name="ask_for_role")
@Views({
//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @view-base-ask_for_role@
 @View(
  name="base",
  members=
        ""  
        + "username  ; "
        + "email  ; "
        + "role  ; "
  ),
//MP-MANAGED-UPDATABLE-ENDING
 @View(
  name="Create", 
  extendsView="base"
 ),
 @View(
  name="Update", 
  extendsView="base",
        members=
          ""  
 ),
 @View(extendsView="base",
        members=
          ""  
 ),
    @View(name="askForRoleDEFAULT_VIEW", 
    members=
          " username ;"  
        + "email  ; "
        + "roleTransient  ; "
 ),
//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @view-reference-ask_for_role@
    @View(name="reference", 
       extendsView="askForRoleDEFAULT_VIEW"
//MP-MANAGED-UPDATABLE-ENDING
    )
})

//MP-MANAGED-ADDED-AREA-BEGINNING @class-annotation@
//MP-MANAGED-ADDED-AREA-ENDING @class-annotation@
public class AskForRoleIn {

     @Id @Column(name="username" ,length=255)
    private String username; 

//MP-MANAGED-ADDED-AREA-BEGINNING @email-field-annotation@
//MP-MANAGED-ADDED-AREA-ENDING @email-field-annotation@

//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @ATTRIBUTE-email@
    @Column(name="email",  length=255, nullable=false,  unique=false)
    @Required
    @Stereotype ("EMAIL")
    private String email;
//MP-MANAGED-UPDATABLE-ENDING

//MP-MANAGED-ADDED-AREA-BEGINNING @role_TRANSIENT-field-annotation@
//MP-MANAGED-ADDED-AREA-ENDING @role_TRANSIENT-field-annotation@

//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @ATTRIBUTE-role_TRANSIENT@
 @Transient
 @ReadOnly
    private String roleTransient;
//MP-MANAGED-UPDATABLE-ENDING


//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @parent-Role-ask_for_role@
    @ManyToOne (fetch=FetchType.LAZY ,optional=false) 
    @JoinColumn(name="role", referencedColumnName = "ID", nullable=false,  unique=false  )
    @ReferenceView ("reference") 
    private Role role;

...
} 
Although not persisted and never looked up AskForRoleIn can be used by Openxava:
  •  to pass by information as a DTO
  • perform validation
  • perform assignment (it is linked to table Role)
  • it contains a transient field roleTransient that will be used by the Openxava action to copy the 'role' field of the 'role' table (not the pk)
  • offers a view with
    • simple input field
    • associated entities
  • @Id is associated to one field (otherwise JPA/Hibernate complains)

Action


/**
 * template reference : 
 * - name      : ActionOX.SDD.query
 * - file name : ActionOX.SDD.query.vm
 * - time      : 2013/08/22 AD at 12:29:41 CEST
*/
package net.sf.mp.demo.porphyry.sdd.action.statement;

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

import org.openxava.jpa.*;
import org.openxava.model.*;
import org.openxava.util.*;
import org.openxava.validators.*;
import org.openxava.actions.*;
import java.util.*;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.hibernate.HibernateException;
import org.hibernate.Session;

import net.sf.mp.demo.porphyry.sdd.out.statement.AskForRoleOutList;
import net.sf.mp.demo.porphyry.sdd.out.statement.AskForRoleOut;
import net.sf.mp.demo.porphyry.sdd.in.statement.AskForRoleIn;

public class AskForRoleAction extends ViewBaseAction {

    public static final String QUERY_NATIVE = "call ask_for_role (?,?,?)";

//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @SDD_EXECUTE_GET-ask_for_role@
    public AskForRoleOutList execute (AskForRoleIn askForRoleIn) {
        AskForRoleOutList askForRoleOutList = new AskForRoleOutList();
        List list = executeJDBC (askForRoleIn);
        askForRoleOutList.setAskForRoleOuts (list);
        return askForRoleOutList;
    }
//MP-MANAGED-UPDATABLE-ENDING

//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @SDD_EXECUTE_JDBC-ask_for_role@
 public List<askforroleout> executeJDBC(AskForRoleIn askForRoleIn) {
  if (askForRoleIn==null)
   askForRoleIn = new AskForRoleIn();
  List<askforroleout> list = new ArrayList<askforroleout>();
  PreparedStatement pstmt = null;
  ResultSet rs = null;
  Connection conn = null;
  try {
   conn = getConnection();
   pstmt = conn.prepareStatement(QUERY_NATIVE);
            if (askForRoleIn.getUsername()==null) {
               pstmt.setNull(1, java.sql.Types.VARCHAR);
            } else {
               pstmt.setString(1, askForRoleIn.getUsername()); 
            }
            if (askForRoleIn.getEmail()==null) {
               pstmt.setNull(2, java.sql.Types.VARCHAR);
            } else {
               pstmt.setString(2, askForRoleIn.getEmail()); 
            }
            if (askForRoleIn.getRoleTransient()==null) {
               pstmt.setNull(3, java.sql.Types.VARCHAR);
            } else {
               pstmt.setString(3, askForRoleIn.getRoleTransient()); 
            }
   rs = pstmt.executeQuery();
  } catch (Exception e) {
        e.printStackTrace();
     } finally {
       try {
         rs.close();
         pstmt.close();
         conn.close();
       } catch (Exception e) {
         e.printStackTrace();
       }
     }
  return list;
 }
//MP-MANAGED-UPDATABLE-ENDING

//if JPA2 implementation is hibernate
    @SuppressWarnings("deprecation")   
    public Connection getConnection() throws HibernateException {  
        Session session = getSession();  
        Connection connection = session.connection();  
        return connection;  
    } 
    
    private Session getSession() {  
        Session session = (Session) XPersistence.getManager().getDelegate();  
        return session;  
    }

 public void execute() throws Exception {
//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @execute-porphyry@
        //super.execute();
        //TODO
        Messages errors = 
            MapFacade.validate("AskForRoleIn", getView().getValues());
        if (errors.contains()) throw new ValidationException(errors);
        AskForRoleIn e = new AskForRoleIn();
 e.setUsername((String)getView().getValue("username"));
 e.setEmail((String)getView().getValue("email"));

 // parent to copy to transient field
        Map roleMap = (Map)getView().getValue("role");
        if (roleMap!=null) {
  e.setRoleTransient ((String)roleMap.get("role"));
        }
  
        try {
            execute(e);
        } catch (Exception ex) {
            errors = new Messages();
            errors.add(ex.getMessage());
            throw new ValidationException(errors);
        }
        //TODO return list
        addInfo("call AskForRoleAction done!");
//MP-MANAGED-UPDATABLE-ENDING

 }

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

} 
  • perform validation
  • retrieve simple type as well as complex (Role object type)
  • copy values a input of the store proc call
    • here the store proc does not return anything so there is no parsing of the resultset.
Here one can argue that we do not need the transient field 'roleTransient' in AskForRoleIn.
This is true. It is present because it was easier from a generation point of view to keep the parameter order of the stored procedure call.

Controller.xml


<controllers> 
    <!-- statement driven development SDD -->
  <!-- $table.name -->
 <controller name="AskForRoleController">
  <action name="askForRole" mode="detail" class="net.sf.mp.demo.porphyry.sdd.action.statement.AskForRoleAction" >
   <use-object name="xava_view" />
  </action>     
 </controller>
</controllers> 
Provides controller and action

Application.xml


<application name="porphyry"> 

    <!-- statement driven development SDD -->
 <module name="AskForRoleIn" >
     <model name="AskForRoleIn"/>
     <view name="base"/> 
     <controller name="AskForRoleController"/>
     <mode-controller name="DetailOnly"/>
 </module>
 
</application>

Wiring between Model/View/Controller and mode
Detail mode selected (ie no lookup)

Screens

Input screen 

Available at ${yourcontext}/xava/home.jsp?application=porphyry&module=AskForRoleIn
Is also available as a menu entry under statement

 Sub select Use case


 

 

Performing the action

Viewing the result


Since it is store in table USER_ROLE_REQUEST
Minuteproject generates also a CRUD access on this table.
By filtering we check that the input of the store proc+ additional business field are stored correctly.



 

Conclusion

Statement Driven Development - SDD
  • provides tooling for analyst
  • RAD for developer 
    • any sql statement could now be an advance business UC (sub affection, validation)
    • necessary OX gearing is generated.
  • is a pillar of development productivity
Minuteproject is also generating portlet.xml in order to deploy 'Transient-definition portlet' on portal such as Liferay.


Friday, August 17, 2012

sql query to primefaces app with sdd

Intro

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

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

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

Enrichment

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

statement-driven-development

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

        ....
   <statement-model>
                <queries>
                     <query name="get addresses by criteria" id="c">
                         <query-body><value>
<![CDATA[select * from address where latitude between ? and ? and longitude between ? and ? and lcase(city) like ?]]>
                            </value></query-body>
                         <query-params>
                             <query-param name="latitude_lower_limit" is-mandatory="false" type="DOUBLE" sample="37"></query-param>
                             <query-param name="latitude_upper_limit" type="DOUBLE" sample="38"></query-param>
                             <query-param name="longitude_lower_limit" type="DOUBLE" sample="-122"></query-param>
                             <query-param name="longitude_upper_limit" type="DOUBLE" sample="-123"></query-param>
                             <query-param name="city" type="STRING" sample="'S'" convert="lowercase,append%" default="%"/>
                         </query-params>
                     </query>
                </queries>
            </statement-model>
  </model> 

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

Empower primefaces with minuteproject sdd templates

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

 

Steps

Set-up

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

 

Generated code

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

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

Deployment

Setup

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

Deploy

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

 

Result

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

Create address

List addresses

SDD in action: Use specific criteria to address

Check validation

 

Future

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

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

Wednesday, May 30, 2012

RigaJUG demo - REST - SDD

On the model
You want to extract some info via sql such as

select k.key_name, t.translation, t.date_finalization, l.code, l.description, tl.first_name, tl.last_name, tl.email 
from translation t, language l, user tl, translation_key k
where
t.language_id = l.idlanguage
and tl.idUser = t.translator_id
and k.id = t.key_id
order by key_name

And you want to parametarize the extraction by passing some filtering input
select k.key_name, t.translation, t.date_finalization, l.code, l.description, tl.first_name, tl.last_name, tl.email 
from translation t, language l, user tl, translation_key k
where
t.language_id = l.idlanguage
and tl.idUser = t.translator_id
and k.id = t.key_id
and k.key_name like ?
and l.code like ?
order by key_name
limit ?

And you want to have a REST access!
And you want it NOW!

Good news SDD Statement Driven Development is there for you!

From the above statement you can extract 3 info:
  • an input (in java a DTO bean) with keyName, code, limit as params
  • an output  (in java a DTO bean) with keyName, translation, dateFinalization, code, description, firstName, lastName, email
  • a functionality to name
This is enough to get a REST-CXF application instantly!
This page will show you how to reach it!

Intro

This page correspond to a demo to belonging to a more global presentation.
To be able to demostrate it there are couple of prerequisits:
  • download minuteproject 0.8.1+
  • install maven
  • install tomcat
  • install mysql and create the schema (see demo JPA2)
This page will show you how to:
  • configure
  • generate
  • build
  • deploy
  • test

Configuration

Minuteproject works with a configuration file that indicates:

  • where is the model
  • how to enrich it
    • enable Statement Driven Development declartion
  • against which technologies to generate (targets)

Here is the configuration TRANXY-JPA2-Spring-REST-CXF-SDD.xml
<!DOCTYPE root>
<generator-config xmlns="http://minuteproject.sf.net/xsd/mp-config" 
xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" 
xs:noNamespaceSchemaLocation="../config/mp-config.xsd">
 <configuration>
  <conventions>
   <target-convention type="enable-updatable-code-feature" />
  </conventions>
  <model name="tranxy" version="1.0" package-root="net.sf.mp.demo">
   <data-model>
    <driver name="mysql" version="5.1.16" groupId="mysql"
     artifactId="mysql-connector-java"></driver>
    <dataSource>
     <driverClassName>org.gjt.mm.mysql.Driver</driverClassName>
     <url>jdbc:mysql://127.0.0.1:3306/tranxy</url>
     <username>root</username>
     <password>mysql</password>
    </dataSource>
    <primaryKeyPolicy oneGlobal="false" >
     <primaryKeyPolicyPattern name="autoincrementPattern"></primaryKeyPolicyPattern>
    </primaryKeyPolicy>
   </data-model>
   <business-model>
    <generation-condition>
     <condition type="exclude" startsWith="QUARTZ"></condition>
    </generation-condition>
    <business-package default="tranxy">
     <condition type="package" startsWith="trans" result="translation"></condition>
    </business-package>
    <enrichment>
     <conventions>
      <!-- manipulate the structure and entities BEFORE manipulating the 
       entities -->
      <column-naming-convention type="apply-strip-column-name-suffix"
       pattern-to-strip="ID" />
      <reference-naming-convention
       type="apply-referenced-alias-when-no-ambiguity" is-to-plurialize="true" />
     </conventions>
          <entity name="language_x_translator">
              <field name="language_id" linkReferenceAlias="translating_language" />
              <field name="user_id" linkReferenceAlias="translator" />
          </entity>
          <entity name="LANGUAGE_X_SPEAKER">
              <field name="LANGUAGE_ID" linkToTargetEntity="LANGUAGE"
                  linkToTargetField="IDLANGUAGE" linkReferenceAlias="spoken_language" />
              <field name="user_id" linkReferenceAlias="speaker" />
          </entity>
          <entity name="APPLICATION">
              <field name="TYPE">
                  <property tag="checkconstraint" alias="application_type">
                      <property name="OPENSOURCE"/>
                      <property name="COPYRIGHT" />
                  </property>
              </field>
          </entity>
    </enrichment>
   </business-model>
      <statement-model>
         <queries>
             <query name="get translation info">
                 <query-body><value>
<![CDATA[select k.key_name, t.translation, t.date_finalization, l.code, l.description, tl.first_name, tl.last_name, tl.email from translation t, language l, user tl, translation_key k where t.language_id = l.idlanguage and tl.idUser = t.translator_id and k.id = t.key_id and k.key_name like ? and l.code like ? order by key_name limit ?]]>
                    </value></query-body>
                 <query-params>
                     <query-param name="key" is-mandatory="false" type="STRING" sample="'test'"></query-param>
                     <query-param name="code" is-mandatory="false" type="STRING" sample="'FR'"></query-param>
                     <query-param name="max" is-mandatory="false" type="INT" sample="10"></query-param>
                 </query-params>
             </query>
          </queries>
      </statement-model>
  </model>
  <targets>
            
      <target refname="REST-CXF-BSLA" 
         name="default" 
         fileName="mp-template-config-REST-CXF-Spring.xml" 
         outputdir-root="../../DEV/latvianjug/tranxy/rest"
         templatedir-root="../../template/framework/cxf">
      </target>

      <target refname="BackendOnBsla" 
         name="default" 
         fileName="mp-template-config-JPA2-bsla.xml" 
         outputdir-root="../../DEV/latvianjug/tranxy/bsla"
         templatedir-root="../../template/framework/bsla">
          <property name="add-cache-implementation" value="ehcache"></property>
      </target> 
      
   <target refname="JPA2" fileName="mp-template-config-JPA2.xml"
    outputdir-root="../../DEV/latvianjug/tranxy/jpa" 
        templatedir-root="../../template/framework/jpa">
    <property name="add-querydsl" value="2.1.2"></property>
    <property name="add-jpa2-implementation" value="hibernate"></property>
        <property name="add-cache-implementation" value="ehcache"></property>
        <property name="add-domain-specific-method" value="true"></property>
        <property name="add-xmlbinding" value="true"></property> 
        <property name="add-xml-format" value="lowercase-hyphen"></property> 
   </target>
   
      <target refname="SDD-beans" 
          outputdir-root="../../DEV/latvianjug/tranxy/jpa"
         fileName="mp-template-config-SDD-beans.xml" 
         templatedir-root="../../template/framework/bean">
         <property name="add-xmlbinding" value="true"></property> 
         <property name="add-xml-format" value="lowercase-hyphen"></property>
      </target>

      <target refname="COMMON-LIB" 
         fileName="mp-template-config-COMMON-LIB.xml" 
         templatedir-root="../../template/framework/common">
      </target>   
                        
      <target refname="MavenMaster" 
         name="maven" 
         fileName="mp-template-config-maven.xml" 
         outputdir-root="../../DEV/latvianjug/tranxy"
         templatedir-root="../../template/framework/maven">
      </target>

      <target refname="CACHE-LIB" fileName="mp-template-config-CACHE-LIB.xml"
          templatedir-root="../../template/framework/cache">
      </target>
      
   <target refname="LIB" fileName="mp-template-config-bsla-LIB-features.xml"
    templatedir-root="../../template/framework/bsla">
   </target>

      <target refname="REST-LIB" 
         fileName="mp-template-config-REST-LIB.xml" 
         templatedir-root="../../template/framework/rest">
      </target>
      <target refname="SPRING-LIB" 
         fileName="mp-template-config-SPRING-LIB.xml" 
         templatedir-root="../../template/framework/spring">
      </target>

  </targets>
 </configuration>
</generator-config>
Aside of the 'standard' CXF CRUD generation (see on demo). Here a set of new artifacts are generated to enable the enriched 'get translation infos' function.
The part of the configuration may seem a bit long, I agree. It describes what templates and metadata file to use.
I plan to have simplify version à la minuteproject console where you just reference a track name belonging to a catalog and pass some properties.
The set of target currently displayed can be copied from the sample provided in /demo/config.

Generation

Drop TRANXY-JPA2-Spring-REST-CXF-SDD.xml in /mywork/config and run: model-generation.cmd/sh TRANXY-JPA2-Spring-REST-CXF-SDD.xml
Generated artifacts go to /DEV/latvianjug/tranxy.

Generated artifacts

Here are presented on the new artifacts of the CXF-JPA2 track.
The artifacts are presented from a top down perspective (starting from REST-Frontend down to Persistence layer).
The name of the artifacts are deeply linked to the query name 'get translation info'.

REST resources

2 resources file are generated, one for json rendering the other for xml.

GetTranslationInfoJsonResource.java

/**
 * Copyright (c) minuteproject, minuteproject@gmail.com
 * All rights reserved.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License")
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * More information on minuteproject:
 * twitter @minuteproject
 * wiki http://minuteproject.wikispaces.com 
 * blog http://minuteproject.blogspot.net
 * 
*/
/**
 * template reference : 
 * - name : CXFSpringSDDJsonResource
 * - file name : CXFSpringSDDResource.vm
*/
package net.sf.mp.demo.tranxy.rest.statement;

//MP-MANAGED-ADDED-AREA-BEGINNING @import@
//MP-MANAGED-ADDED-AREA-ENDING @import@
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import java.io.*;
import java.sql.*;

import javax.servlet.http.*;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.FormParam;
import javax.ws.rs.QueryParam;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import javax.xml.bind.JAXBElement;

import net.sf.mp.demo.tranxy.sdd.out.statement.GetTranslationInfoOutList;
import net.sf.mp.demo.tranxy.sdd.in.statement.GetTranslationInfoIn;
import net.sf.mp.demo.tranxy.dao.sdd.face.statement.GetTranslationInfoDaoFace;
/**
 *
 * <p>Title: GetTranslationInfoJsonResource</p>
 *
 * <p>Description: remote interface for GetTranslationInfoJsonResource service </p>
 *
 */
@Produces ({MediaType.APPLICATION_JSON})
@Consumes ({MediaType.APPLICATION_JSON})
@Service ("getTranslationInfoJsonResource")
@Transactional
@Path ("/rest/json/gettranslationinfos")
public class GetTranslationInfoJsonResource {

    @Autowired
    @Qualifier("getTranslationInfoDaoFace")
    GetTranslationInfoDaoFace getTranslationInfoDaoFace;

//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @SDD_EXECUTE_GET-get translation info@
    @GET
    @Produces (MediaType.APPLICATION_JSON) 

    public GetTranslationInfoOutList executeAndFormatXml (
        @QueryParam ("key") String key ,
        @QueryParam ("code") String code ,
        @QueryParam ("max") Integer max ) {
        return execute(
           key ,
           code ,
           max   
  );
    }
//MP-MANAGED-UPDATABLE-ENDING

//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @SDD_EXECUTE_GET-get translation info@
    public GetTranslationInfoOutList execute (
        String key ,
        String code ,
        Integer max ) {
  GetTranslationInfoIn getTranslationInfoIn = new GetTranslationInfoIn ();
  getTranslationInfoIn.setKey (key);
  getTranslationInfoIn.setCode (code);
  getTranslationInfoIn.setMax (max);
        return getTranslationInfoDaoFace.execute(getTranslationInfoIn);
    }
//MP-MANAGED-UPDATABLE-ENDING

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

}

GetTranslationInfoXmlResource.java

/**
 * Copyright (c) minuteproject, minuteproject@gmail.com
 * All rights reserved.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License")
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * More information on minuteproject:
 * twitter @minuteproject
 * wiki http://minuteproject.wikispaces.com 
 * blog http://minuteproject.blogspot.net
 * 
*/
/**
 * template reference : 
 * - name : CXFSpringSDDXmlResource
 * - file name : CXFSpringSDDResource.vm
*/
package net.sf.mp.demo.tranxy.rest.statement;

//MP-MANAGED-ADDED-AREA-BEGINNING @import@
//MP-MANAGED-ADDED-AREA-ENDING @import@
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import java.io.*;
import java.sql.*;

import javax.servlet.http.*;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.FormParam;
import javax.ws.rs.QueryParam;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import javax.xml.bind.JAXBElement;

import net.sf.mp.demo.tranxy.sdd.out.statement.GetTranslationInfoOutList;
import net.sf.mp.demo.tranxy.sdd.in.statement.GetTranslationInfoIn;
import net.sf.mp.demo.tranxy.dao.sdd.face.statement.GetTranslationInfoDaoFace;
/**
 *
 * <p>Title: GetTranslationInfoXmlResource</p>
 *
 * <p>Description: remote interface for GetTranslationInfoXmlResource service </p>
 *
 */
@Produces ({MediaType.APPLICATION_XML})
@Consumes ({MediaType.APPLICATION_XML})
@Service ("getTranslationInfoXmlResource")
@Transactional
@Path ("/rest/xml/gettranslationinfos")
public class GetTranslationInfoXmlResource {

    @Autowired
    @Qualifier("getTranslationInfoDaoFace")
    GetTranslationInfoDaoFace getTranslationInfoDaoFace;

//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @SDD_EXECUTE_GET-get translation info@
    @GET
    @Produces (MediaType.APPLICATION_XML) 

    public GetTranslationInfoOutList executeAndFormatXml (
        @QueryParam ("key") String key ,
        @QueryParam ("code") String code ,
        @QueryParam ("max") Integer max ) {
        return execute(
           key ,
           code ,
           max   
  );
    }
//MP-MANAGED-UPDATABLE-ENDING

//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @SDD_EXECUTE_GET-get translation info@
    public GetTranslationInfoOutList execute (
        String key ,
        String code ,
        Integer max ) {
  GetTranslationInfoIn getTranslationInfoIn = new GetTranslationInfoIn ();
  getTranslationInfoIn.setKey (key);
  getTranslationInfoIn.setCode (code);
  getTranslationInfoIn.setMax (max);
        return getTranslationInfoDaoFace.execute(getTranslationInfoIn);
    }
//MP-MANAGED-UPDATABLE-ENDING

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

}

Spring configuration

application-context.xml

It is adapted to reflect the new beans
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xmlns:jaxrs="http://cxf.apache.org/jaxrs"
 xsi:schemaLocation="
  http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  http://www.springframework.org/schema/context 
  http://www.springframework.org/schema/context/spring-context-3.0.xsd
  http://www.springframework.org/schema/tx
  http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
  http://cxf.apache.org/jaxrs
  http://cxf.apache.org/schemas/jaxrs.xsd">

    <import resource="classpath:META-INF/cxf/cxf.xml" />
    <import resource="classpath:META-INF/cxf/cxf-extension-jaxrs-binding.xml" />
    <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
    
    <context:component-scan base-package="net.sf.mp.demo.tranxy.rest"/>
    <context:component-scan base-package="net.sf.mp.demo.tranxy.dao.sdd.impl"/>

    <import resource="classpath:net/sf/mp/demo/tranxy/factory/spring/spring-config-Tranxy-BE-main.xml"/>    
 
    <jaxrs:server id="restContainer" address="/">
        <jaxrs:serviceBeans>
   <!-- tranxy --> 
   <ref bean="applicationResource"/>
   <ref bean="languageResource"/>
   <ref bean="userResource"/>
   <!-- translation --> 
   <ref bean="translationResource"/>
   <ref bean="translationKeyResource"/>
   <ref bean="translationRequestResource"/>
 
   <!-- statements -->
   <ref bean="getTranslationInfoXmlResource"/>
   <ref bean="getTranslationInfoJsonResource"/>
        </jaxrs:serviceBeans>
    </jaxrs:server> 

</beans> 

DAO layer

Interface GetTranslationInfoDaoFace.java

/**
 * Copyright (c) minuteproject, minuteproject@gmail.com
 * All rights reserved.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License")
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * More information on minuteproject:
 * twitter @minuteproject
 * wiki http://minuteproject.wikispaces.com 
 * blog http://minuteproject.blogspot.net
 * 
*/
/**
 * template reference : 
 * - name : SDDDaoInterface
 * - file name : SDDDaoInterface.vm
*/
package net.sf.mp.demo.tranxy.dao.sdd.face.statement;

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

import net.sf.mp.demo.tranxy.sdd.out.statement.GetTranslationInfoOutList;
import net.sf.mp.demo.tranxy.sdd.in.statement.GetTranslationInfoIn;

/**
 *
 * <p>Title: GetTranslationInfoDaoFace</p>
 *
 * <p>Description: remote interface for GetTranslationInfoDaoFace service </p>
 *
 */
public interface GetTranslationInfoDaoFace {

//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @SDD_EXECUTE_GET-get translation info@
    public GetTranslationInfoOutList execute (GetTranslationInfoIn getTranslationInfoIn) ;
//MP-MANAGED-UPDATABLE-ENDING

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


} 

Implementation GetTranslationInfoRepository.java

/**
 * Copyright (c) minuteproject, minuteproject@gmail.com
 * All rights reserved.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License")
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * More information on minuteproject:
 * twitter @minuteproject
 * wiki http://minuteproject.wikispaces.com 
 * blog http://minuteproject.blogspot.net
 * 
*/
/**
 * template reference : 
 * - name : SDDSpringJPADao
 * - file name : SDDSpringJPADao.vm
*/
package net.sf.mp.demo.tranxy.dao.sdd.impl.statement;

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

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.hibernate.HibernateException;
import org.hibernate.Session;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import net.sf.mp.demo.tranxy.sdd.out.statement.GetTranslationInfoOutList;
import net.sf.mp.demo.tranxy.sdd.out.statement.GetTranslationInfoOut;
import net.sf.mp.demo.tranxy.sdd.in.statement.GetTranslationInfoIn;
import net.sf.mp.demo.tranxy.dao.sdd.face.statement.GetTranslationInfoDaoFace;

/**
 *
 * <p>Title: GetTranslationInfoRepository</p>
 *
 * <p>Description: SDD DAO Spring JPA implementation </p>
 *
 */
@Repository ("getTranslationInfoDaoFace")
@Transactional(propagation = Propagation.REQUIRED) 
public class GetTranslationInfoRepository implements GetTranslationInfoDaoFace{

 public static final String QUERY_NATIVE = "select k.key_name, t.translation, t.date_finalization, l.code, l.description, tl.first_name, tl.last_name, tl.email from translation t, language l, user tl, translation_key k where t.language_id = l.idlanguage and tl.idUser = t.translator_id and k.id = t.key_id and k.key_name like ? and l.code like ? order by key_name limit ?";

 @PersistenceContext(unitName = "tranxy")  
    EntityManager entityManager;  
//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @SDD_EXECUTE_GET-get translation info@
    public GetTranslationInfoOutList execute (GetTranslationInfoIn getTranslationInfoIn) {
  GetTranslationInfoOutList getTranslationInfoOutList = new GetTranslationInfoOutList();
  List<GetTranslationInfoOut> list = executeJDBC (getTranslationInfoIn);
  getTranslationInfoOutList.setGetTranslationInfoOuts (list);
        return getTranslationInfoOutList;
    }
//MP-MANAGED-UPDATABLE-ENDING

//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @SDD_EXECUTE_JDBC-get translation info@
 public List<GetTranslationInfoOut> executeJDBC(GetTranslationInfoIn getTranslationInfoIn) {
  List<GetTranslationInfoOut> list = new ArrayList<GetTranslationInfoOut>();
  PreparedStatement pstmt = null;
  ResultSet rs = null;
  Connection conn = null;
  try {
   conn = getConnection();
   pstmt = conn.prepareStatement(QUERY_NATIVE);
   pstmt.setString(1, getTranslationInfoIn.getKey()); 
   pstmt.setString(2, getTranslationInfoIn.getCode()); 
   pstmt.setInt(3, getTranslationInfoIn.getMax()); 
   rs = pstmt.executeQuery();
   while (rs.next()) {
    GetTranslationInfoOut getTranslationInfoOut = new GetTranslationInfoOut();
    getTranslationInfoOut.setKeyName(rs.getString(1)); 
    getTranslationInfoOut.setTranslation(rs.getString(2)); 
    getTranslationInfoOut.setDateFinalization(rs.getString(3)); 
    getTranslationInfoOut.setCode(rs.getString(4)); 
    getTranslationInfoOut.setDescription(rs.getString(5)); 
    getTranslationInfoOut.setFirstName(rs.getString(6)); 
    getTranslationInfoOut.setLastName(rs.getString(7)); 
    getTranslationInfoOut.setEmail(rs.getString(8)); 
    list.add(getTranslationInfoOut);
         }
  } catch (Exception e) {
        e.printStackTrace();
     } finally {
       try {
         rs.close();
         pstmt.close();
         conn.close();
       } catch (Exception e) {
         e.printStackTrace();
       }
     }
  return list;
 }
//MP-MANAGED-UPDATABLE-ENDING

//if JPA2 implementation is hibernate
 @SuppressWarnings("deprecation")   
    public Connection getConnection() throws HibernateException {  
  Session session = getSession();  
  Connection connection = session.connection();  
  return connection;  
    } 
 
    private Session getSession() {  
     Session session = (Session) entityManager.getDelegate();  
     return session;  
    }
 
//MP-MANAGED-ADDED-AREA-BEGINNING @implementation@
//MP-MANAGED-ADDED-AREA-ENDING @implementation@

}

Beans!!

Welcome back DTO! You do not need to re-wrap your sql against ORM!
Go straight: your I/O = your DTOs

Input bean

GetTranslationInfoIn.java


/**
 * Copyright (c) minuteproject, minuteproject@gmail.com
 * All rights reserved.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License")
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * More information on minuteproject:
 * twitter @minuteproject
 * wiki http://minuteproject.wikispaces.com 
 * blog http://minuteproject.blogspot.net
 * 
*/
/**
 * template reference : 
 * - name : SDDInputBean
 * - file name : JavaBean.vm
*/
package net.sf.mp.demo.tranxy.sdd.in.statement;

import java.util.List;
import java.util.ArrayList;

//MP-MANAGED-ADDED-AREA-BEGINNING @import@
//MP-MANAGED-ADDED-AREA-ENDING @import@
/**
 *
 * <p>Title: GetTranslationInfoIn</p>
 *
 * <p>Description: Java Bean containing a collection of GetTranslationInfo </p>
 *
 */
public class GetTranslationInfoIn {

    private String key;
    private String code;
    private Integer max;

    /**
    * Default constructor
    */
    public GetTranslationInfoIn() {
    }
 
    public String getKey() {
        return key;
    }
 
    public void setKey (String key) {
        this.key =  key;
    }

    public String getCode() {
        return code;
    }
 
    public void setCode (String code) {
        this.code =  code;
    }

    public Integer getMax() {
        return max;
    }
 
    public void setMax (Integer max) {
        this.max =  max;
    }


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

Output beans

GetTranslationInfoOut


/**
 * Copyright (c) minuteproject, minuteproject@gmail.com
 * All rights reserved.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License")
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * More information on minuteproject:
 * twitter @minuteproject
 * wiki http://minuteproject.wikispaces.com 
 * blog http://minuteproject.blogspot.net
 * 
*/
/**
 * template reference : 
 * - name : SDDOutputBean
 * - file name : JavaBean.vm
*/
package net.sf.mp.demo.tranxy.sdd.out.statement;

import java.util.List;
import java.util.ArrayList;

//MP-MANAGED-ADDED-AREA-BEGINNING @import@
//MP-MANAGED-ADDED-AREA-ENDING @import@
/**
 *
 * <p>Title: GetTranslationInfoOut</p>
 *
 * <p>Description: Java Bean containing a collection of GetTranslationInfo </p>
 *
 */
public class GetTranslationInfoOut {

    private String keyName;
    private String translation;
    private String dateFinalization;
    private String code;
    private String description;
    private String firstName;
    private String lastName;
    private String email;

    /**
    * Default constructor
    */
    public GetTranslationInfoOut() {
    }
 
    public String getKeyName() {
        return keyName;
    }
 
    public void setKeyName (String keyName) {
        this.keyName =  keyName;
    }

    public String getTranslation() {
        return translation;
    }
 
    public void setTranslation (String translation) {
        this.translation =  translation;
    }

    public String getDateFinalization() {
        return dateFinalization;
    }
 
    public void setDateFinalization (String dateFinalization) {
        this.dateFinalization =  dateFinalization;
    }

    public String getCode() {
        return code;
    }
 
    public void setCode (String code) {
        this.code =  code;
    }

    public String getDescription() {
        return description;
    }
 
    public void setDescription (String description) {
        this.description =  description;
    }

    public String getFirstName() {
        return firstName;
    }
 
    public void setFirstName (String firstName) {
        this.firstName =  firstName;
    }

    public String getLastName() {
        return lastName;
    }
 
    public void setLastName (String lastName) {
        this.lastName =  lastName;
    }

    public String getEmail() {
        return email;
    }
 
    public void setEmail (String email) {
        this.email =  email;
    }


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

GetTranslationInfoOutList


/**
 * Copyright (c) minuteproject, minuteproject@gmail.com
 * All rights reserved.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License")
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * More information on minuteproject:
 * twitter @minuteproject
 * wiki http://minuteproject.wikispaces.com 
 * blog http://minuteproject.blogspot.net
 * 
*/
/**
 * template reference : 
 * - name : SDDOutputBeanCollection
 * - file name : JavaBeanCollection.vm
*/
package net.sf.mp.demo.tranxy.sdd.out.statement;

import java.util.List;
import java.util.ArrayList;

import javax.xml.bind.annotation.*;

import net.sf.mp.demo.tranxy.sdd.out.statement.GetTranslationInfoOut;

//MP-MANAGED-ADDED-AREA-BEGINNING @import@
//MP-MANAGED-ADDED-AREA-ENDING @import@
/**
 *
 * <p>Title: GetTranslationInfoOutList</p>
 *
 * <p>Description: Java Bean GetTranslationInfoOutList </p>
 *
 */
@XmlRootElement (name="GetTranslationInfoOutList")
public class GetTranslationInfoOutList {

    @XmlElement (name="GetTranslationInfoOut") //(name="gettranslationinfoouts")
    private List<GetTranslationInfoOut> getTranslationInfoOuts;

    /**
    * Default constructor
    */
    public GetTranslationInfoOutList() {
    }
 
    public void setGetTranslationInfoOuts (List<GetTranslationInfoOut> getTranslationInfoOuts) {
        this.getTranslationInfoOuts = getTranslationInfoOuts;
    }

    @XmlTransient
    public List<GetTranslationInfoOut> getGetTranslationInfoOuts () {
        if (getTranslationInfoOuts==null)
            getTranslationInfoOuts = new ArrayList<GetTranslationInfoOut>();
        return getTranslationInfoOuts;
    }

    public void addGetTranslationInfoOut (GetTranslationInfoOut getTranslationInfoOut) {
        getGetTranslationInfoOuts ().add(getTranslationInfoOut);
    }


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

Improvements

SDD concept is brand new inside minuteproject, a number of improvement are foreseen:
  • error handling
  • validation (type, mandatory)
  • default value

Build deploy and test

Build

Run >mvn clean package from the root application

Deploy

Drop the resulting artefact tranxyRestCxfApp.war in tomcat/webapps
Start tomcat

Test

2 URLs - one for json format the other for xml format are available

REST URL with parameters returning json format
http://localhost:8080/tranxyRestCxfApp/rest/json/gettranslationinfos?key=%25&code=%25&max=2
Search for all key : % and all code : % and max number of return value is 2
REST URL with parameters returning xml format
Search for all key : % and all code : % and max number of return value is 1

Now you can enjoy and make cool front-end (ajax, jquery friendly and other js).

Conclusion

If you want to go fast, and when working with ORM abstraction takes to long, then have a look at Statement Driven Development.

The war between pro Domain Object vs. DTO is irrelevant for Minuteproject.
On this project both live aside.
Use the approach that best suits your needs.


Friday, May 18, 2012

Minuteproject reverse-engineering short stories

Latvian JUG Riga presentation abstract

I have been contacted by the Latvian JUG to make a demonstration-oriented presentation over Minuteproject. This page covers the agenda of what I intend to show at Riga.
All the demos will start from scratch i.e. a DB model that is evolving across the presentation.
Main demos will target technologies: JPA2, REST, Spring, CXF, Openxava for reverse-engineering.
A new feature of Minuteproject is introduced: Statement Driven Development with a demostration for REST track.
Eventually a last demo will show how to get instantly a web site with Openxava.

Agenda

  • Minuteproject overview
  • Demo 1
    • Model sample (3 tables)
    •  JPA2 track generation
    • code review
    • write unit test
    • alter and customize generated code (ex: with validation annotations)
  • Enrichment facilities
    • Customisation
    • Declaritive conventions
  • Demo 2
    • Model has changed! (10+ tables)
    • generation & code review (convensions, what happened to your modified code?)
  • Generated-code integration technics
  • RESTIFY your backend
  • Demo 3
    • Add REST track on top of JPA2
    • Generate for REST-CXF/SpringMVC
    • Deploy on tomcat and test
  • SDD - Statement Driven Development
  • Demo 4
    • Add custom statement
    • Generate for REST
    • Deploy on tomcat and test
  • Goodies...
  • Demo 5 
    • Get instantly an Openxava web app
    • Deploy on tomcat and test
  • Extend Minuteproject
    • Add your own templates and tracks
  • Conclusion
  • FAQ

Wednesday, May 16, 2012

Statement driven development WYSIWYG for REST

In my previous article, I mentioned that minuteproject will have statement driven development features.
This page I disclose the potential of SDD while developing REST application.
Regarding the technologies I take:
  • REST with CXF
  • Spring Bean for DAO
  • JPA2 as persistence layer
Original WYSIWYG is revisited into What You STATE Is What You Get.

As fundamentals you need a Statement with is surrounding I/O.
The model against which the statement is applied is important but secundary.

As example for SQL, I take 3 queries:
  • select * from address where latitude between ? and ? and longitude between ? and ? and lcase(city) like ?
  • select * from address where addressid between ? and ?
  • select * from address where lcase(city) like ?
Those queries must be given 
  • a name
  • an input (replace question marks by sample value and provide name)
  • an output (deduce from the metadata recieved after executing the query)
And basically that's it.

Thursday, May 10, 2012

Statement driven development

Today most methodologies used model oriented approach.
It can be domain-driven or reverse-engineering, one common point is that they start from a static definition of a model. For domain-driven, it is the domain issued by the development language itself. For the reverse-engineering it starts from a static model structure definition ex: a xsd, wsdl, database schema.
Statement driven development focuses on the actions the developer can run on some models and not the models themselves.
Example: a select statement fetching all the group members a user with group-administrator-role can manage.
Here the statement can be materialized into a search query with sql as implementation.
The important thing for the developer is the query and its I/O not really the underneath model and ... not the decorative technology.

Why Statement-Driven-Development

Couple of articles and limitations make me think that statement driven approach can be a flexible and fast alternative for developpers.
Usually after defining an abstract model such as ORM, the user have to write his UC statements. This means that there is still this second step to perform.


The model is sometimes/often overkill. As a developer, you do not have to apprehend the entire model complexity before yielding productivity.

Limitation on standard

Like in the JOOQ article about function and stored procedure extracting the meta-information can reach some limits when entering in vendor specific particularities.

Native DSL

There is a trend that states that SQL is the only DSL you need.
Why should you wrap it with other technology abstraction that limit its power?

Bye-Bye Domain Objects

...Welcome DTO.
I/O are by essence DTO (why should they be the exact reflection of a persistence layer?). This situation is just a specific exception.
This exception is widely used by multiple apps/framework (strong resuability but limitations).
Remark:
This article is not there to cover the 'everlasting-debate' DO vs. DTO.
SDD just brings a new approach that do not exclude but complement the DDD/Rev-Eng one.

Concretely

MinuteProject for release 0.8.1+ (mid-may-2012) will offer Statement-Driven-Development facilities.

  • The user will focus one SQL statement.
  • The output will be deduce by the execution of it.
  • The input will be easily configurable.

Example

Here is a simple configuration. Statement-model is the new node.

  <model>
    ...
      <statement-model>
           <queries>
               <query name="get address street">
                  <query-body><value><![CDATA[select * from address where addressid > ?]]></value></query-body>
                  <query-params>
                      <query-param name="identifier_Address" is-mandatory="false" type="INT" sample="1"></query-param>
                  </query-params>
               </query>
           </queries>
      </statement-model>
  </model>

This configuration should be enough to get:
  • Input bean
  • Output bean
  • Output list bean
  •  All the technology decoration ex for 
    • REST CXF: 
      • Resource bean with REST path
      • spring config
      • Native DAO
Demonstration will be shipped in Minuteproject next release (0.8.1).

Integrating with REST is pretty much statement-driven: basically you just need to know the URL + its I/O.

Conclusion

  • With SDD you focus on the statement and the I/O.
  • Minuteproject simplifies the rest (technology wrapper).