Thursday, September 6, 2012

Adding MP 4 ADF-BC-SDO track

Intro

In order to add a new track on minuteproject we have to understand the target architecture, the target architecture artifacts and the link between them.
This article focuses on what contains ADF Faces project for manipulating (CRUD) RDBMS contains, and how are ADF Faces artifacts reference each other.
The goal is to provide a MP 4 ADF roadmap: to have an ADF application very quickly based on reverse-engineering facilities of minuteproject using some navigation defaulting.
On top of this a SDO stack can also be generated.
This is a lean process so, comments are welcomed!

 

Context

I am a ADF newbie so point discussed here might changed.
I start from what is generated by JDeveloper and follow the tutorials to create an ADF web app.

 

ADF Model Artifact Overview

 When create a webapp 2 ADF projects are created: Model and ViewControler.
This part focuses on the model artifacts.
The following artifacts are placed under the technical package 'model'.
The overview help defining the minuteproject artifact metadata.

AppModule.xml

It catalogs the views and view links usage.
One Artifact per model, and has a fix name.

Entity.xml

Holds the description of the database entity, mapping information, keys with validation, accessorAttributes. Can be considered to some extends as Domain Objects.
It is per DB entity, it does not depend of other xml artifacts.
Can sometimes reference Impl.java that gives custom implementation.

View-name.xml

Correspond to a access (select) of some Domain Object, contains view attributes.
It depends on .xml, it is referenced by AppModule.xml
Multiple view can exist for an entity. So the question is how to deduce the name of the view.
The view can be deduced:
  • a default one: with all selection
  • a reference one: based on the semantic reference of the entity
  • search ones: based on the fact that a field is searchable (entity enrichment in MP).

 Assoc.xml

 Define a relationship between entity, master part, cardinality...
Is dependent on the .xml
One per relationship

View-link.xml

 Define the view of the Assoc.xml. 
One per Assoc.xml file.
Referenced in AppModule.xml

Bundles artifacts for views 

View can have bundles for internationalisation

Other artifacts

Model.jpx
ModelBundle.properties


ViewController artifacts overview


Todo

SDO artifacts overview

At the view Level

View-nameSDOImpl.java

Linked to the view-name.xml

View-nameSDO.java

Linked to the view-name.xml

View-nameSDO.xsd

Linked to the view-name.xml


Service interface

At the application level

AppModuleServiceImpl.java

Java class
Stateless webservice done with EJB and Oracle annotations

AppModuleService.java

Java interface
JAX-WS annotation
Defines methods of WS

AppModuleService.wsdl

Wsdl containing messages, portType, binding, services
Importing static schema as well as AppModuleService.xsd

AppModuleService.xsd

xsd that import static oracle xsd as well as view-nameSDO.xsd
defines types used in AppModuleService.wsdl

ADF artifacts

Todo

 

References

http://docs.oracle.com/cd/E18941_01/tutorials/toc.htm

http://www.oracle.com/technetwork/developer-tools/adf/documentation/adf-faces-rc-demo-083799.html

http://www.oracle.com/technetwork/developer-tools/jdev/index-095536.html

http://go2kavinkumar.wordpress.com/2011/08/28/using-viewcriteria-in-find-operation-of-adf-bc-service/



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, July 18, 2012

Minuteproject with databases

Intro

Minuteproject works with different relational databases.
In the distribution, test have been done over couple of DB (oracle, mysql...). Meanwhile your database might not be present in the list.
This article summarizes the step to follow to add your database type and test it with minuteproject.

Driver

Add your driver

Minuteproject works over jdbc to retrieve the database metadata. So you need a driver.
Download your jdbc driver and add it in /application/lib/extra

Operation


From the config

You have to add in the data-source node
  • driver
  • url
  • username
  • password 
 Add in schema node
  • schema (should be the same as user) in the schema node.

From the console

The console choose its target database from the database-catalog.xml file located in /catalog
If you open it add a new entry similar to the previous one specifying what is your default primary-key strategy and other information.

Feed back

Feed-backs are welcomed to improve the catalog of database available.

Friday, July 13, 2012

working generated updatable code with MP 4 Openxava

Intro

In this article the user will learn how to keep Openxava modified-generated code based on Minuteproject 4 updatable code.

Summary

Minuteproject offers generated code for Openxava technology.
We will generate one project.
Make a build to get:
  • a working OX Defaulting app
  • a OX workspace
Alter the code
Generate again and ensure that your modification are kept.

MP 4 OX updatable code

Minuteproject provides for updatable code fonctionalities.
When you generate for Openxava, you have to specify that the generated code goes into the OX workspace.
This is because the MP 4 OX is a two-step process.
  • The first you generate the OX code.
  • The second, when you execute build-.cmd/sh, you:
    • build the OX workspace and copy the generated code
    • compile, package, deploy

The code that you modify is the code of the workspace so it generated code should point to the workspace.

If you choose another directory for generation, the process will work fine the first time and all the time you working with reverse-engineering only. But if you alter your code, then when you make the second operation then your modification are erased.

When the generation points to the workspace then only once the two-step process is needed. The second step initiates the project into the workspace.
Once done, no need to run the second step again.
You can alter both your generated code (as described here)
You can also alter your DB model and generate again, your modifications are generation-safe.

Example

Under construction
This example show how to add business rules with ABL and JSR303 into the Minuteproject generated code for OX.
It use Minuteproject 0.8.2 and Openxava 4.5

Add sample config

Generate

Build workspace

Alter code

Alter model

Regenerate

Test

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.


Wednesday, May 23, 2012

RigaJUG - demo - instant OPENXAVA app

From the following model called Tranxy

we'll generate instantly an Openxava app.

The interesting part of this demo is the enrichment of the model, it is described Riga demo 2 (The main complexity comes by having 2 tables (language and user) linked by 2 many-to-many).

Actions

There are four simple actions make it happened:
  • Drop TRANXY-OPENXAVA.xml in /mywork/config and run: model-generation.cmd/sh TRANXY-OPENXAVA.xml
  • In /output/OPENXAVA set the 2 environment variables
    • set OX_HOME=../openxava-4.4.1 (export on unix)
    • set MP_HOME=../minuteProject-0.8.1 (export on unix)
  • execute >build-tranxy.cmd/sh
And that's it!
Last action will 
  • create an Openxava project
  • build it (portlet included ready for Liferay)
  • start Openxava embedded tomcat server
  • add connection datasource
  • deploy the build application on tomcat
  • start a browser connection at  http://localhost:8080/tranxy/xava/homeMenu.jsp where the menu is.

The application works on an empty database, you can use the Openxava-Minuteproject-generated-app to
populate it...
Enjoy!

Prerequisits

MinuteProject installed 
Openxava installed 
Ant installed
Model Tranxy (script) installed on an up-and-running Mysql server
Java 1.6

Configuration

TRANXY-OPENXAVA.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>
                <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-fix-primary-key-column-name-when-no-ambiguity" 
                      default-value="ID"/>  
              <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" />
              <reference-naming-convention type="apply-many-to-many-aliasing" is-to-plurialize="true"/>
             </conventions>
                  <entity name="language_x_translator">
                      <field name="language_id" linkReferenceAlias="translating_language" linkToTargetEntity="LANGUAGE"/>
                      <field name="user_id" linkReferenceAlias="translator" linkToTargetEntity="USER"/>
                  </entity>
                  <entity name="LANGUAGE_X_SPEAKER">
                      <field name="LANGUAGE_ID" linkToTargetEntity="LANGUAGE"
                          linkToTargetField="IDLANGUAGE" linkReferenceAlias="spoken_language" />
                      <field name="user_id" linkReferenceAlias="speaker" linkToTargetEntity="USER"/>
                  </entity>
                  <entity name="APPLICATION" alias="registered application">
                      <field name="TYPE" alias="obedience">
                          <property tag="checkconstraint" alias="application_type">
                              <property name="OPENSOURCE"/>
                              <property name="COPYRIGHT" />
                          </property>
                      </field>
                  </entity>
                  <entity name="LANGUAGE" content-type="reference-data"/>
            </enrichment>
            </business-model>
        </model>
        <targets>
        
            <target refname="OpenXava" 
               name="OpenXava" 
               fileName="mp-template-config-openxava-last-features.xml" 
               outputdir-root="../../dev/latvianjug/output/OPENXAVA"
               templatedir-root="../../template/framework/openxava">
            </target> 
            <target refname="JPA2-LIB" 
               fileName="mp-template-config-JPA2-LIB.xml" 
               templatedir-root="../../template/framework/jpa">
            </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>

        </targets>
    </configuration>
</generator-config>

Screenshots

Add an application

Customise Translation Column




RigaJUG - demo - REST CXF

In this demo, we will generate a REST/CXF application with spring/jpa2 backend.
This demo presents the track REST-CXF of minuteproject.

The model from demo 2 remains the same.

The enrichment stays the same.

But the tracks changes
What is added are 2 layers:
  • a DAO layer with spring integration on top of JPA2
  • a REST-CXF layer with JAX-RS annotation
The JPA2 entities are annotated by JAXB annotations.

All this is done to provide a CRUD interface on top of the model entities.

Configuration

Here is the configuration TRANXY-JPA2-Spring-REST-CXF.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>
  </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="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>

It is possible to enrich each link of the many-to-many relationship table (ex: language_x_translator and language_x_speaker) to provide the other side relationship with an alias and thus avoid long composite variable name.

Generation

Set TRANXY-JPA2-Spring-REST-CXF.xml in /mywork/config
Run
>model-generation.cmd TRANXY-JPA2-Spring-REST-CXF.xml
The output goes in /dev/latvianjug/tranxy

Resulting artefacts

A maven project structure with 3 modules
  • JPA2 layer
  • Spring DAO layer
  • CXF layer
JPA2 layer has been visited in Demo 1 and Demo 2.

Spring DAO layer

It consists of transactional services one for each entity

CRUD DAO layer on top of JPA2: This layer is called BSLA (Basic Spring Layer Architecture).

Two interfaces and implementation are generated for each entity
Example for Translation entity

DAO Interfaces

/**
 * 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 : BslaDaoInterfaceUML
 * - file name : BslaDaoInterfaceUML.vm
*/
package net.sf.mp.demo.tranxy.dao.face.translation;

import net.sf.mp.demo.tranxy.domain.translation.Translation;
import java.util.List;
import net.sf.minuteProject.architecture.bsla.bean.criteria.PaginationCriteria;
import net.sf.minuteProject.architecture.bsla.dao.face.DataAccessObject;


/**
 *
 * <p>Title: TranslationDao</p>
 *
 * <p>Description: Interface of a Data access object dealing with TranslationDao
 * persistence. It offers a set of methods which allow for saving,
 * deleting and searching translation objects</p>
 *
 */
public interface TranslationDao extends DataAccessObject {

    /**
     * Inserts a Translation entity 
     * @param Translation translation
     */
    public void insertTranslation(Translation translation) ;
 
    /**
     * Inserts a list of Translation entity 
     * @param List<Translation> translations
     */
    public void insertTranslations(List<Translation> translations) ;
        
    /**
     * Updates a Translation entity 
     * @param Translation translation
     */
    public Translation updateTranslation(Translation translation) ;

  /**
     * Updates a Translation entity with only the attributes set into Translation.
  * The primary keys are to be set for this method to operate.
  * This is a performance friendly feature, which remove the udibiquous full load and full update when an
  * update is to be done
   * Remark: The primary keys cannot be update by this methods, nor are the attributes that must be set to null.
   * @param Translation translation
   */
    public int updateNotNullOnlyTranslation(Translation translation) ;
  
 public int updateNotNullOnlyPrototypeTranslation(Translation translation, Translation prototypeCriteria);
 
     /**
     * Saves a Translation entity 
     * @param Translation translation
     */
    public void saveTranslation(Translation translation);
    
    /**
     * Deletes a Translation entity 
     * @param Translation translation
     */
    public void deleteTranslation(Translation translation) ;
 
    /**
     * Loads the Translation entity which is related to an instance of
     * Translation
     * @param Long id
     * @return Translation The Translation entity
     
    public Translation loadTranslation(Long id);
*/
    /**
     * Loads the Translation entity which is related to an instance of
     * Translation
     * @param java.lang.Long Id
     * @return Translation The Translation entity
     */
    public Translation loadTranslation(java.lang.Long id);    

    /**
     * Loads a list of Translation entity 
     * @param List<java.lang.Long> ids
     * @return List<Translation> The Translation entity
     */
    public List<Translation> loadTranslationListByTranslation (List<Translation> translations);
    
    /**
     * Loads a list of Translation entity 
     * @param List<java.lang.Long> ids
     * @return List<Translation> The Translation entity
     */
    public List<Translation> loadTranslationListById(List<java.lang.Long> ids);
    
    /**
     * Loads the Translation entity which is related to an instance of
     * Translation and its dependent one to many objects
     * @param Long id
     * @return Translation The Translation entity
     */
    public Translation loadFullFirstLevelTranslation(java.lang.Long id);
    
    /**
     * Loads the Translation entity which is related to an instance of
     * Translation
     * @param Translation translation
     * @return Translation The Translation entity
     */
    public Translation loadFullFirstLevelTranslation(Translation translation);    
    
    
    /**
     * Loads the Translation entity which is related to an instance of
     * Translation and its dependent objects one to many
     * @param Long id
     * @return Translation The Translation entity
     */
    public Translation loadFullTranslation(Long id) ;

    /**
     * Searches a list of Translation entity based on a Translation containing Translation matching criteria
     * @param Translation translation
     * @return List<Translation>
     */
    public List<Translation> searchPrototypeTranslation(Translation translation) ;
    
    /**
     * Searches a list of Translation entity based on a list of Translation containing Translation matching criteria
     * @param List<Translation> translations
     * @return List<Translation>
     */
    public List<Translation> searchPrototypeTranslation(List<Translation> translations) ;    
     
 /**
     * Searches a list of Translation entity 
     * @param Translation translation
     * @return List
     */
    public List<Translation> searchPrototypeTranslation(Translation translationPositive, Translation translationNegative) ;
        
    /**
     * Load a paginated list of Translation entity dependent of pagination criteria
     * @param PaginationCriteria paginationCriteria
     * @return List
     */
    public List<Translation> loadPaginatedTranslation (Translation translation, PaginationCriteria paginationCriteria) ;
            
}

/**
 * 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 : BslaDaoInterfaceExtendedUML
 * - file name : BslaDaoInterfaceKFUML.vm
*/
package net.sf.mp.demo.tranxy.dao.face.translation;

import net.sf.mp.demo.tranxy.domain.translation.Translation;
import java.util.List;
import net.sf.minuteProject.architecture.filter.data.Criteria;
import net.sf.minuteProject.architecture.bsla.dao.face.DataAccessObject;

/**
 *
 * <p>Title: TranslationExtDao</p>
 *
 * <p>Description: Interface of a Data access object dealing with TranslationExtDao
 * persistence. It offers extended DAO functionalities</p>
 *
 */
public interface TranslationExtDao extends DataAccessObject {
     
     /**
     * Inserts a Translation entity with cascade of its children
     * @param Translation translation
     */
    public void insertTranslationWithCascade(Translation translation) ;
    
    /**
     * Inserts a list of Translation entity with cascade of its children
     * @param List<Translation> translations
     */
    public void insertTranslationsWithCascade(List<Translation> translations) ;        
   
    /**
     * lookup Translation entity Translation, criteria and max result number
     */
    public List<Translation> lookupTranslation(Translation translation, Criteria criteria, Integer numberOfResult);
 
 public Integer updateNotNullOnlyTranslation (Translation translation, Criteria criteria);

 /**
  * Affect the first translation retrieved corresponding to the translation criteria.
  * Blank criteria are mapped to null.
  * If no criteria is found, null is returned.
  */
    public Translation affectTranslation (Translation translation);
    
    public Translation affectTranslationUseCache (Translation translation);
     
 /**
  * Assign the first translation retrieved corresponding to the translation criteria.
  * Blank criteria are mapped to null.
  * If no criteria is found, null is returned.
  * If there is no translation corresponding in the database. Then translation is inserted and returned with its primary key(s). 
  */
    public Translation assignTranslation (Translation translation);

 /**
  * Assign the first translation retrieved corresponding to the mask criteria.
  * Blank criteria are mapped to null.
  * If no criteria is found, null is returned.
  * If there is no translation corresponding in the database. 
  * Then translation is inserted and returned with its primary key(s). 
  * Mask servers usually to set unique keys or the semantic reference
  */
    public Translation assignTranslation (Translation translation, Translation mask);
 
    public Translation assignTranslationUseCache (Translation translation);
         
    /**
    * return the first Translation entity found
    */           
    public Translation getFirstTranslation (Translation translation);
    
    /**
    * checks if the Translation entity exists
    */           
    public boolean existsTranslation (Translation translation);    
    
    public boolean existsTranslationWhereConditionsAre (Translation translation);

    /**
    * partial load enables to specify the fields you want to load explicitly
    */            
    public List<Translation> partialLoadTranslation(Translation translation, Translation positiveTranslation, Translation negativeTranslation);

    /**
    * partial load with parent entities
    * variation (list, first, distinct decorator)
    * variation2 (with cache)
    */
    public List<Translation> partialLoadWithParentTranslation(Translation translation, Translation positiveTranslation, Translation negativeTranslation);

    public List<Translation> partialLoadWithParentTranslationUseCache(Translation translation, Translation positiveTranslation, Translation negativeTranslation, Boolean useCache);

    public List<Translation> partialLoadWithParentTranslationUseCacheOnResult(Translation translation, Translation positiveTranslation, Translation negativeTranslation, Boolean useCache);

    /**
    * variation first
    */
    public Translation partialLoadWithParentFirstTranslation(Translation translationWhat, Translation positiveTranslation, Translation negativeTranslation);
    
    public Translation partialLoadWithParentFirstTranslationUseCache(Translation translationWhat, Translation positiveTranslation, Translation negativeTranslation, Boolean useCache);

    public Translation partialLoadWithParentFirstTranslationUseCacheOnResult(Translation translationWhat, Translation positiveTranslation, Translation negativeTranslation, Boolean useCache);

    /**
    * variation distinct
    */
    public List<Translation> getDistinctTranslation(Translation translationWhat, Translation positiveTranslation, Translation negativeTranslation);

    //
    public List partialLoadWithParentForBean(Object bean, Translation translation, Translation positiveTranslation, Translation negativeTranslation);

    /**
    * search on prototype with cache
    */
    public List<Translation> searchPrototypeWithCacheTranslation (Translation translation);
      
    
    /**
     * Searches a list of distinct Translation entity based on a Translation mask and a list of Translation containing Translation matching criteria
     * @param Translation translation
     * @param List<Translation> translations
     * @return List<Translation>
     */
    public List<Translation> searchDistinctPrototypeTranslation(Translation translationMask, List<Translation> translations) ;    

 public List<Translation> countDistinct (Translation whatMask, Translation whereEqCriteria);
 
 public Long count (Translation whereEqCriteria);
 
 public List<Translation> loadGraph(Translation graphMaskWhat, List<Translation> whereMask);  
 
 public List<Translation> loadGraphFromParentKey (Translation graphMaskWhat, List<Translation> parents); 
 
    /**
     * generic to move after in superclass
     */
    public List<Object[]> getSQLQueryResult(String query);     
 
}

DAO implementations

TranslationJPAImpl and TranslationJPAExtImpl (code not copied).

In the future Generic DAO will be used for cross-entity redundant aspects.
Adaptation to spring 3.x will be perform (i.e no more JPASupport extension by EntityManager injection)
Meanwhile the code here above works fine with spring 2.5+

Spring configurations

spring-config-Tranxy-BE-main.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

    <!-- Dao JPA -->
    <import resource="classpath:net/sf/mp/demo/tranxy/factory/spring/spring-config-JPA-Tranxy-dao.xml"/>    

<!--MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @JPAtranxyFactory-tranxy@-->
    <!-- hibernate config to put in an appart config file-->
    <bean id="JPAtranxyFactory" autowire="byName"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <!-- all connection information are retrieve from the persistence file-->
  <!--
   <property name="dataSource" ref="..."/>
   <property name="persistenceUnitName" value="..."/>
  -->
        <property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml" />
    </bean>
<!--MP-MANAGED-UPDATABLE-ENDING-->
    <!-- Database -->
    <import resource="classpath:net/sf/mp/demo/tranxy/factory/spring/spring-config-Tranxy-database.xml"/>    

</beans>

spring-config-Tranxy-database.xml
<?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:jndi="http://www.springframework.org/schema/jee"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                           http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
                           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
                           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">


    <bean id="placeHolderConfig"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location"><value>classpath:net/sf/mp/demo/tranxy/factory/spring/spring-config-Tranxy.properties</value></property>
    </bean>     
 
    <bean id="tranxyTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="JPAtranxyFactory"/>
    </bean>

    <!-- to get the entity manager -->
    <tx:annotation-driven transaction-manager="tranxyTransactionManager"/>
    
</beans>

spring-config-Tranxy-BE-main
jdbc.tranxy.driverClassName=org.gjt.mm.mysql.Driver
jdbc.tranxy.url=jdbc:mysql://127.0.0.1:3306/tranxy
jdbc.tranxy.username=root
jdbc.tranxy.password=mysql
jdbc.tranxy.jndi=jdbc/tranxy
hibernate.dialect=org.hibernate.dialect.MySQLDialect

spring-config-JPA-Tranxy-dao.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

    <!-- Import Dao definitions for business components -->

   <!-- tranxy -->
   <import resource="classpath:net/sf/mp/demo/tranxy/factory/spring/tranxy/dao-JPA-Tranxy.xml"/>
   <!-- translation -->
   <import resource="classpath:net/sf/mp/demo/tranxy/factory/spring/translation/dao-JPA-Translation.xml"/>

    <!-- Import Ext Dao definitions for business components -->
   <!-- tranxy extended dao -->
   <import resource="classpath:net/sf/mp/demo/tranxy/factory/spring/tranxy/dao-ext-JPA-Tranxy.xml"/>
   <!-- translation extended dao -->
   <import resource="classpath:net/sf/mp/demo/tranxy/factory/spring/translation/dao-ext-JPA-Translation.xml"/>

</beans>

dao-JPA-Translation.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>

    <bean id="translationDao" class="net.sf.mp.demo.tranxy.dao.impl.jpa.translation.TranslationJPAImpl" singleton="false" >
        <property name="entityManagerFactory"><ref bean="JPAtranxyFactory"/></property>
    </bean>
    <bean id="translationKeyDao" class="net.sf.mp.demo.tranxy.dao.impl.jpa.translation.TranslationKeyJPAImpl" singleton="false" >
        <property name="entityManagerFactory"><ref bean="JPAtranxyFactory"/></property>
    </bean>
    <bean id="translationRequestDao" class="net.sf.mp.demo.tranxy.dao.impl.jpa.translation.TranslationRequestJPAImpl" singleton="false" >
        <property name="entityManagerFactory"><ref bean="JPAtranxyFactory"/></property>
    </bean>

</beans>
It is the same for the dao-ext-JPA-Translation.xml, dao-ext-JPA-Tranxy.xml, dao-JPA-Tranxy.xml files

But wait a minute... How can I unit test?
You need two other artifacts before writting your own test.
One is persistence.xml...
Again? Yes, with a embedded connection pool, because the shipped with the build of your JPA2 layer may refere a JNDI Datasource (in case the property environment is set to remote).
Since it is under /src/test/resources/META-INF it will override the one in the JPA2 package.

Two is an adapter that extends AbstractTransactionalJUnit4SpringContextTests: it is generated in /src/test/java

package net.sf.mp.demo.tranxy.dao.face;

import javax.sql.DataSource;

import org.apache.commons.lang.StringUtils;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={
     "classpath:net/sf/mp/demo/tranxy/factory/spring/spring-config-Tranxy-BE-main.xml"
})
@TransactionConfiguration(transactionManager = "tranxyTransactionManager") 
@Transactional
public class AdapterTranxyTestDao extends AbstractTransactionalJUnit4SpringContextTests { 

 @Override
 @Autowired
 public void setDataSource(@Qualifier(value = "tranxyDataSource") DataSource dataSource) {
    this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
 }
...

CXF layer

Each entity have a Rest Resource artifact with JAX-RS annotations to enable CRUD access.
Example with Translation

/**
 * 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 : CXFSpringEntityResource
 * - file name : CXFSpringEntityResource.vm
*/
package net.sf.mp.demo.tranxy.rest.translation;


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.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.dao.face.translation.TranslationDao;
import net.sf.mp.demo.tranxy.dao.face.translation.TranslationExtDao;
import net.sf.mp.demo.tranxy.domain.translation.Translation;

/**
 *
 * <p>Title: TranslationResource</p>
 *
 * <p>Description: remote interface for TranslationResource service </p>
 *
 */
@Path ("/rest/xml/translations")
@Produces ({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
@Consumes ({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
@Service
@Transactional
public class TranslationResource  {
 

 @Autowired
 @Qualifier("translationDao")
 TranslationDao translationDao;
 
 @Autowired
 @Qualifier("translationExtDao")
 TranslationExtDao translationExtDao;

//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @FIND_ALL-translation@
    @GET
    @Produces ({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) 
    public List<Translation> findAll () {
  List<Translation> r = new ArrayList<Translation>();
        List<Translation> l = translationDao.searchPrototypeTranslation(new Translation());
  for (Translation translation : l) {
   r.add(translation.flat());
  }
  return r;
    }
//MP-MANAGED-UPDATABLE-ENDING

//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @FIND_BY_ID-translation@
    @GET
    @Path("{id}")
    @Produces ({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})  
    public Translation findById (@PathParam ("id") java.lang.Long id) {
        Translation _translation = new Translation ();
  _translation.setId(id);
  _translation = translationExtDao.getFirstTranslation(_translation);
  if (_translation!=null) return _translation.flat();
  return new Translation ();
    }
//MP-MANAGED-UPDATABLE-ENDING

    @DELETE
    @Path("{id}")
    public void delete (@PathParam ("id") Long id) {
        Translation translation = new Translation ();
        translation.setId(id);
        translationDao.deleteTranslation(translation);
    }

    @POST
    @Produces ({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) 
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    public Translation create (
        @FormParam("id") Long id,
        @FormParam("translation") String translation,
        @FormParam("language") Integer language,
        @FormParam("key") Long key,
        @FormParam("isFinal") Short isFinal,
        @FormParam("dateFinalization") Date dateFinalization,
        @FormParam("translator") Long translator,
        @Context HttpServletResponse servletResponse
        ) throws IOException {
        Translation _translation = new Translation (
           id,
           translation,
           language,
           key,
           isFinal,
           dateFinalization,
           translator);
        return save(_translation);
    }

    @PUT
    @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
    public Translation save(JAXBElement<Translation> jaxbTranslation) {
        Translation translation = jaxbTranslation.getValue();
        if (translation.getId()!=null)
            return translationDao.updateTranslation(translation);
        return save(translation);
    }

 public Translation save (Translation translation) {
  translationDao.saveTranslation(translation);
  return translation;
 }


}

And two files for the web application and spring in /src/main/resources/webapp/WEB-INF

Web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <display-name>tranxy CXF REST</display-name>
    <description>tranxy CXF REST access</description>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/application-context.xml</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <servlet>
        <servlet-name>CXFServlet</servlet-name>
        <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>CXFServlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

</web-app>

application-context.xml
<?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"/>

    <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 -->
        </jaxrs:serviceBeans>
    </jaxrs:server> 

</beans>

Package, deployment and test

Package

Before building the package there is a dependency shipped with minuteproject mp-bsla.x.y.jar to install. In /target/mp-bsla/ Run script: maven-install.cmd/sh
Build: >mvn clean package

The result is tranxyRestCxfApp.war in /rest/target

Deployment

Start tomcat
Drop tranxyRestCxfApp.war in /webapps
There is an embedded connection pool, so no configuration is needed on tomcat.

Test

USE `tranxy` ;
DELETE FROM application_x_key;
DELETE FROM translation;
DELETE FROM language_x_translator;
DELETE FROM language_x_speaker;
DELETE FROM request_key;

DELETE FROM application;
DELETE FROM translation_key;
DELETE FROM user;
DELETE FROM language;

INSERT INTO application (idapplication,  name, description, type) VALUES (-1,'Porphyry', 'OS application holding environment app', 'OPENSOURCE');
INSERT INTO application (idapplication,  name, description, type) VALUES (-2,'Minuteproject', 'Minuteproject app', 'OPENSOURCE');

INSERT INTO user (iduser, first_name, last_name, email) VALUES (-1,'test', 'lastName', 'test@test.me');
INSERT INTO user (iduser, first_name, last_name, email) VALUES (-2,'test2', 'lastName2', 'test2@test.me');

INSERT INTO language (idlanguage, code, description, locale) VALUES (-1, 'FR', 'France', 'fr');
INSERT INTO language (idlanguage, code, description, locale) VALUES (-2, 'ES', 'Spanish', 'es');                                                                                               
INSERT INTO language (idlanguage, code, description, locale) VALUES (-3, 'EN', 'English', 'en');          

INSERT INTO language_x_translator (language_id, user_id) VALUES (-1, -1);
INSERT INTO language_x_translator (language_id, user_id) VALUES (-2, -1);
INSERT INTO language_x_speaker (language_id, user_id) VALUES (-1, -1);
INSERT INTO language_x_speaker (language_id, user_id) VALUES (-2, -1);
   
INSERT INTO language_x_translator (language_id, user_id) VALUES (-1, -2);
INSERT INTO language_x_translator (language_id, user_id) VALUES (-2, -2);
INSERT INTO language_x_translator (language_id, user_id) VALUES (-3, -2);    

INSERT INTO translation_key (id, key_name, description) VALUES (-1, 'msg.user.name', 'user name');
INSERT INTO translation (id, translation, language_id, key_id, is_final, date_finalization, translator_id) 
VALUES (-1, 'nom', -1, -1, 1, '2012-04-04', -1);
INSERT INTO translation (id, translation, language_id, key_id, is_final, date_finalization, translator_id) 
VALUES (-2, 'apellido', -1, -2, 1, CURDATE(), -1);                                                                                                               
Now enter
http://localhost:8080/tranxyRestCxfApp/rest/xml/languages to get all the languages

This is the result

Now enter
http://localhost:8080/tranxyRestCxfApp/rest/xml/users/-1 to get the first user

This is the result

Conclusion

This article presented you how to get quickly a CRUD REST interface on top of your DB model.
Of course, you may not need CRUD for all entities and may you need more coarse grain functions to manipulate your model.
Next article will present you how with Statement Driven Development we can get closer to Use Case.