Showing posts with label sql. Show all posts
Showing posts with label sql. Show all posts

Wednesday, August 28, 2013

performance magnitude ft. sql java xml

This page is NOT a benchmark but the performance feeling that I experienced working with those 3 technologies.

While processing data 

SQL runs 100+ faster than JAVA which runs 100+ faster than XML


Is this impression true?
Do you have some magnitude order?

Do feed-back your impressions and results!

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 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).






Saturday, September 3, 2011

SQL select to web application in couple of seconds

Maybe you are not aware but if you just know how to write one sql select statement, you're just couple of seconds from having an web application and couple of minutes from enjoying it as a Liferay portlet.
The key ingredients for this recipe are: Openxava, Liferay and ... Minuteproject.

The equation is:
sql select statement (containing one field considered as unique) = Openxava (Webapp) + Liferay (Portlet)
in less than 5 minutes.

Prerequisites
  • Download Openxava (4.2.2), Liferay, Minuteproject (0.5.7.1+)
  • Set environment variables OX_HOME and MP_HOME to Openxava and Minuteproject home directories respectively.
  • Use Java 6
Create your statement
  • Create a sql select statement
  • Ensure that one of the return field can be considered as unique (if not add one)
  • Create a view from your statement
    • Ex: CREATE VIEW abc as
Remark:
Why is it necessary to have a unique field?
It is to ensure that MP can place a @Id JPA2 annotation on one field of the generated entity.
It has to be unique to avoid issue dealing with first level cache.

Start Minuteproject console
  • Point to your model and fill your model name (ex: efg)
  • select your view abc (in customisation tab)
  • add the unique field as 'virtual' primary key. Your unique field is not a PK but it will acts as to uniquely identify a record entry.
  • Choose target openxava and click generate.
Release your application
  • go to the generated code
  • check environment variables (OX_HOME, MP_HOME) are set.
  • execute from a command prompt: build-efg.cmd/sh
  • depending on the OS from couple of seconds to a dozen of seconds and a browser should open to the address http://localhost:8080/egf/xava/homeMenu.jsp
Deploy on Liferay
  • go to OX_HOME/workspace.dist/efg.dist/efg.war
  • add ejb.jar and jdbc driver jar in LIFERAY_HOME/tomcat/lib
  • start Liferay
  • Upload your portlet
  • Install your portlet
  • Enjoy
Remark:
Whether on the standalone tomcat app or on the Liferay deployed portlet, Openxava is only offering the user selection. It is normal since the DB object is a view, Minuteproject 4 Openxava suppress the Create/Update/Delete, just the Select functionality is kept.


Example

As model I take the lazuly model project in version 0.1 it contains 13 tables.
The sql to create the schema on mysql can be downloaded at http://code.google.com/p/lazuly/source/browse/trunk/conference-db/conference-db-mysql-0.1.sql

Create your view from your sql select statement


Start MinuteProject console


Scope your model


Generate
Choose your technology: here Openxava, and click on Generate.
The code will be generated in MP_HOME/output/conference/OpenXava

Make a standalone Openxava app
Go to the generated code
Open a prompt
Check or set OX_HOME and MP_HOME
execute build-conference.cmd/sh
Couple of seconds later a browser should open to the model (conference) menu.
Report tab has one entry 'my conference cool report'.
When clicking on it here is a sample screen with data that you could see:



Deploy on Liferay
  • Add the datasource (the snippet for tomcat is in OX_HOME/workspace/conference/OpenXava/openxava/other/tomcat/snippet/conference_jndi_for_tomcat_snippet.txt is to be inserted into LIFERAY_HOME/tomcat/conf/context.xml)
  • Upload the portlet war (OX_HOME/workspace.dist/conference.dist/conference.war
  • Position it
  • Enjoy.




Other information

You can also find other information regarding Minuteproject 4 Openxava generation at

Conclusion
  • Your model is your technology tutorial
  • Productivity can be greatly improved
  • Data Quality and troubleshooting operations are quickly available
  • Keep on improving send feed-back to minuteproject@gmail.com or tweet @minuteproject