edwin Posts

A Simple Java Client Server Application using EJB3 and Glassfish3

Well, in this tutorial i want to show you how to create a simple client server application using java. Actually java has dozens of different network protocols, from a simple socket, hessian, burlap, SpringHttpInvoker, SOAP, XML and so on. But in this example, i will try to create a very simple client server application with EJB 3, using Glassfish 3 as JavaEE Container. As usual, i use Netbeans 6.9 with its default Glassfish3 installation.

First, i create a new JavaEE, EJB Module project, named CompressedEJBServer, and create a simple Stateless Session Bean in it

package com.edw.facade;

import javax.ejb.Remote;

/**
 *
 * @author edw
 */
@Remote
public interface ConnectionFacadeRemote {
    String sayHello(String string);
    int sayAge(int age);  
}

and its implementation

package com.edw.facade;

import javax.ejb.Stateless;

/**
 *
 * @author edw
 */
@Stateless
public class ConnectionFacade implements ConnectionFacadeRemote {

    public String sayHello(String string) {
        System.out.println("im at " + this.getClass().getName() + " method sayHello()");
        return "hello " + string;
    }

    public int sayAge(int age) {
        System.out.println("im at " + this.getClass().getName() + " method sayAge()");
        return age * 2;
    }
}

and that’s my EJB3 Server side files. Simple isn’t it?

Next step is creating a Standard Java Application project, for my EJB3 client application. It consist only 1 java file, for testing connection to the server.

package com.edw.main;

import com.edw.facade.ConnectionFacadeRemote;
import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;
import org.apache.log4j.Logger;

/**
 *
 * @author edw
 */
public class Main {

    private Logger logger = Logger.getLogger(Main.class);

    private void connect() {
        try {
            Properties props = new Properties();
            props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.enterprise.naming.SerialInitContextFactory");
            props.setProperty("org.omg.CORBA.ORBInitialHost", "localhost");
            
            // glassfish default port value will be 3700, 
            // but im using tcpviewer to redirect my 50005 port to 3700
            props.setProperty("org.omg.CORBA.ORBInitialPort", "50005");

            InitialContext ctx = new InitialContext(props);
            ConnectionFacadeRemote connectionFacadeRemote = (ConnectionFacadeRemote) ctx.lookup("com.edw.facade.ConnectionFacadeRemote");
            logger.debug(connectionFacadeRemote.sayHello("edwin "));
            logger.debug("my age is " + connectionFacadeRemote.sayAge(12) + " years");
        } catch (Exception ex) {
            logger.error(ex.getMessage(), ex);
        }
    }

    public static void main(String[] args) {
        Main x = new Main();
        x.connect();
    }
}

include these jars to your client side’s application,

auto-depends.jar
common-util.jar
config.jar
config-api.jar
config-types.jar
connectors-internal-api.jar
container-common.jar
deployment-common.jar
dol.jar
ejb.security.jar
ejb-container.jar
glassfish-api.jar
glassfish-corba-asm.jar
glassfish-corba-codegen.jar
glassfish-corba-csiv2-idl.jar
glassfish-corba-newtimer.jar
glassfish-corba-omgapi.jar
glassfish-corba-orb.jar
glassfish-corba-orbgeneric.jar
glassfish-naming.jar
gmbal.jar
hk2-core.jar
internal-api.jar
javax.ejb.jar
javax.jms.jar
javax.resource.jar
javax.servlet.jar
javax.transaction.jar
jta.jar
kernel.jar
management-api.jar
orb-connector.jar
orb-iiop.jar
security.jar
tiger-types-osgi.jar
transaction-internal-api.jar 

and dont forget to add CompressedEJBServer project into CompressEJBClient’s project

this is what happen if i run my client side’s application

[Main] DEBUG com.edw.main.Main:30 - hello edwin 
[Main] DEBUG com.edw.main.Main:31 - my age is 24 years

this is my Server side’s project structures

and this is my Client side’s project structures
My Client Side's Project Structure

and this is my TCP Viewer logs, i try to redirect my localhost’s port 50005 into my localhost’s port 3700 (Glassfish’s port), so i can see what is passing through my 50005 port via TCP Viewer’s console.

Hope this can help, have fun and good luck. May the Source be with You.
(*)

Google+

Creating an Autocomplete Text Field in Java using SwingX

Again, my friend Iswi asked me a simple question, but a little bit hard to do. She asked me, how can she create an autocomplete jtextfield in java, maybe something like NetBean’s autocompletion feature. It took me a while to try several workarounds, before i found a very neat library, swingx. Let just say that this SwingX library helped me alot, and it have lots of other cool swing components. Really worth a try.

In this example, i try to create a simple application consist of 2 autocompletion components, 1 unrestricted jcombobox and 1 restricted jtextfield. Both components will connect to one table using Hibernate. Let’s give it a try.

First, a simple 2 column table.

CREATE DATABASE 'test'
USE 'test'

CREATE TABLE 'contoh' (
  'nama' varchar(30) NOT NULL,
  'alamat' varchar(100) DEFAULT NULL,
  PRIMARY KEY ('nama')
) 

next step is creating a java bean and its hbm.xml for database mapping

package com.edw.bean;

/**
 * Contoh generated by hbm2java
 */
public class Contoh implements java.io.Serializable {

    private String nama;
    private String alamat;

    public Contoh() {
    }

    public Contoh(String nama) {
        this.nama = nama;
    }

    public Contoh(String nama, String alamat) {
        this.nama = nama;
        this.alamat = alamat;
    }

    public String getNama() {
        return this.nama;
    }

    public void setNama(String nama) {
        this.nama = nama;
    }

    public String getAlamat() {
        return this.alamat;
    }

    public void setAlamat(String alamat) {
        this.alamat = alamat;
    }
}

FYI, im using NetBeans’ Hibernate POJO and XML generator.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Sep 1, 2010 10:10:38 AM by Hibernate Tools 3.2.1.GA -->
<hibernate-mapping>
  <class catalog="test" name="com.edw.bean.Contoh" table="contoh">
    <id name="nama" type="string">
      <column length="30" name="nama"/>
      <generator class="assigned"/>
    </id>
    <property name="alamat" type="string">
      <column length="100" name="alamat"/>
    </property>
  </class>
</hibernate-mapping>

this is my hibernate.cfg.xml, for my default hibernate configuration

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/test</property>
    <property name="hibernate.connection.username">admin</property>
    <property name="hibernate.connection.password">xxx</property>
    <mapping resource="com/edw/bean/Contoh.hbm.xml"/>
  </session-factory>
</hibernate-configuration>

and my java class to load hibernate’s main xml configuration

package com.edw.hbm.util;

import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.SessionFactory;

/**
 * Hibernate Utility class with a convenient method to get Session Factory object.
 *
 * @author edw
 */
public class HibernateUtil {
    private static final SessionFactory sessionFactory;

    static {
        try {
            // Create the SessionFactory from standard (hibernate.cfg.xml) 
            // config file.
            sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
        } catch (Throwable ex) {
            // Log the exception. 
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}

this is my main java class, you’ll see some imported SwingX’s classes.

package com.edw.swingx;

import com.edw.bean.Contoh;
import com.edw.hbm.util.HibernateUtil;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JTextField;
import org.apache.log4j.Logger;
import org.hibernate.Session;

import org.jdesktop.swingx.autocomplete.AutoCompleteDecorator;
import org.jdesktop.swingx.combobox.ListComboBoxModel;

/**
 *
 * @author edw
 */
public class AutoCompletionTextField extends JFrame implements ActionListener {

    private JButton button = new JButton("tombol");
    private JComboBox comboComplete = new JComboBox();
    private JTextField textComplete = new JTextField(30);
    private Logger logger = Logger.getLogger(this.getClass());
    private List<String> strings = new ArrayList<String>();

    public void actionPerformed(ActionEvent e) {
        if(e.getSource() == button){
            logger.debug(comboComplete.getSelectedItem().toString());
            logger.debug(textComplete.getText().toString());
        }
    }

    public AutoCompletionTextField() {

        try {
            Session session = HibernateUtil.getSessionFactory().openSession();
            List<Contoh> contohs = (List<Contoh>)session.createCriteria(Contoh.class).list();
            session.close();

            for (Contoh contoh : contohs) {
                strings.add(contoh.getNama());
            }

            Collections.sort(strings);

            // change true to false to enable string restriction
            comboComplete.setEditable(true);
            comboComplete.setModel(new ListComboBoxModel<String>(strings));

            AutoCompleteDecorator.decorate(comboComplete);
            // change true to false to disable string restriction
            AutoCompleteDecorator.decorate(textComplete, strings, true);

            Container con = getContentPane();
            con.setLayout(new FlowLayout());
            con.add(comboComplete);
            con.add(textComplete);
            con.add(button);

            button.addActionListener(this);
            comboComplete.addActionListener(this);
        } catch (Exception ex) {
            logger.error(ex.getMessage(), ex);
        }
    }
    
    public static void main(String[] args) {
        AutoCompletionTextField autoCompletionTextField = new AutoCompletionTextField();
        autoCompletionTextField.setVisible(true);
        autoCompletionTextField.pack();
        autoCompletionTextField.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

this is my UI result,

this is NetBeans 6.9 project structure,

Again, thank you Iswi for your questions. Cheers, (B)

Google+

Calling a JInternalFrame from a JDialog

Yesterday, my friend Iswi asked me a question, how can she called a JinternalFrame from a JDialog, and put it in an existing JDesktopPane? Well Iswi, here are your answers.

First i create a very simple JFrame application

package com.edw.ui;

import java.awt.BorderLayout;
import java.awt.Container;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;

import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import org.apache.log4j.Logger;

/**
 *
 * @author edw
 */
public class FrameMain extends JFrame implements ActionListener {

    private JDesktopPane desktopPane = new JDesktopPane();
    private JMenuBar jMenuBar = new JMenuBar();
    private JMenu menuTest = new JMenu("Test");
    private JMenuItem jMenuItem = new JMenuItem("execute");
    private Logger logger = Logger.getLogger(this.getClass());

    public FrameMain() {
        Container con = getContentPane();  
        con.setLayout(new BorderLayout());
        con.add(desktopPane, BorderLayout.CENTER);

        menuTest.add(jMenuItem);
        jMenuBar.add(menuTest);

        setJMenuBar(jMenuBar);

        jMenuItem.addActionListener(this);
    }

    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == jMenuItem) {
            logger.debug("in jmenuitem");
            InternalTestOne internalTestSatu = new InternalTestOne(this);
            internalTestSatu.setVisible(true);
            getDesktopPane().add(internalTestSatu);
        }
    }

    public static void main(String[] args) {
        FrameMain frameMain = new FrameMain();
        frameMain.setVisible(true);
        frameMain.setLocationRelativeTo(null);        
        frameMain.setSize(800, 500);
        frameMain.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frameMain.setTitle("bubu");
    }

    public JDesktopPane getDesktopPane() {
        return desktopPane;
    }

    public void setDesktopPane(JDesktopPane desktopPane) {
        this.desktopPane = desktopPane;
    }
}

and this is my first JInternalFrame, it will call a JDialog class,

package com.edw.ui;

import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;

import javax.swing.JInternalFrame;
import org.apache.log4j.Logger;

/**
 *
 * @author edw
 */
public class InternalTestOne extends JInternalFrame implements ActionListener {

    private Logger logger = Logger.getLogger(this.getClass());
    private JButton button = new JButton("Klik Dialog");
    private FrameMain frameMain = new FrameMain();

    public void actionPerformed(ActionEvent e) {
        if(e.getSource() == button){
            logger.debug("in ActionPerformed InternalTestSatu");

            // show jdialog
            DialogTest dialogTest = new DialogTest(frameMain);
            dialogTest.setVisible(true);
        }
    }

    public InternalTestOne(FrameMain frameMain) {
        super("internal satu", true, true, true, true);
        this.frameMain = frameMain;
        setSize(300,300);
        logger.debug("in InternalTestSatu");

        Container con = getContentPane();
        con.setLayout(new FlowLayout());
        con.add(button);
        button.addActionListener(this);
    }

}

and this is my JDialog class

package com.edw.ui;

import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;

import org.apache.log4j.Logger;

/**
 *
 * @author edw
 */
public class DialogTest extends JDialog implements ActionListener {

    private JButton button = new JButton("call Internal Frame");
    private Logger logger = Logger.getLogger(this.getClass());
    private FrameMain frameMain = new FrameMain();

    public void actionPerformed(ActionEvent e) {
        if(e.getSource() == button){
            logger.debug("at actionPerformed "+this.getClass().getName());

            // call jinternalframe from here           
            InternalTestTwo internalTestTwo = new InternalTestTwo();
            internalTestTwo.setVisible(true);
            frameMain.getDesktopPane().add(internalTestTwo);
            this.setVisible(false);
            this.dispose();
        }
    }

    public DialogTest(FrameMain frameMain) {
        super(frameMain);
        this.frameMain = frameMain;
        setTitle("Calling JInternalFrame");
        Container con = getContentPane();
        con.setLayout(new FlowLayout());
        con.add(button);
        setLocationRelativeTo(null);
        setSize(300,200);
        pack();
        button.addActionListener(this);
    }

}

and finally, this is my second JInternalFrame , it will be called from a JDialog

package com.edw.ui;

import java.awt.Container;
import java.awt.FlowLayout;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import org.apache.log4j.Logger;

/**
 *
 * @author edw
 */
public class InternalTestTwo extends JInternalFrame {

    private JLabel label = new JLabel("Called from JDialog");
    private Logger logger = Logger.getLogger(this.getClass());

    public InternalTestTwo() {
        super("internal Two Called from JDialog", true, true, true, true);
        setSize(300, 300);
        setLocation(100,200);
        logger.debug("constructor of "+this.getClass().getName());

        Container con = getContentPane();
        con.setLayout(new FlowLayout());
        con.add(label);
    }
}

and this is how my simple app looks like,

Thanks for your questions, Iswi. Always remember, stay hungry, stay foolish.
:-[

Google+

Yet Another Simple Swing, Spring and Ibatis Integration Example

I was working on my side project while drinking a cup of (C) when suddenly i had an idea, why cant i rely on Spring’s Transaction instead of Ibatis’ plain transaction. I see that Spring’s Transaction with annotation is much much simpler than Ibatis’ old fashioned transaction with try-catch and commit-rollback method. Okay, enough with the chit-chat. Let me show you the code.

First, i create a very simple database, with one table consist of 2 simple columns.

CREATE DATABASE 'test'
USE 'test'

CREATE TABLE 'contoh' (
  'nama' varchar(30) NOT NULL,
  'alamat' varchar(100) DEFAULT NULL,
  PRIMARY KEY ('nama')
) 

next step is creating a java bean for database mapping

package com.edw.bean;

public class Contoh {

    private String nama;
    private String alamat;

    public String getAlamat() {
        return alamat;
    }

    public void setAlamat(String alamat) {
        this.alamat = alamat;
    }

    public String getNama() {
        return nama;
    }

    public void setNama(String nama) {
        this.nama = nama;
    }
    
}

and an xml mapping for database queries, i named it contoh.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" 
"http://ibatis.apache.org/dtd/sql-map-2.dtd" >
<sqlMap namespace="contoh" >

  <resultMap id="result" class="com.edw.bean.Contoh">
        <result property="nama" column="NAMA" columnIndex="1"/>
        <result property="alamat" column="ALAMAT" columnIndex="2"/>
    </resultMap>

    <insert id="insertContoh" parameterClass="com.edw.bean.Contoh" >
    insert into contoh (nama, alamat)
    values (#nama:VARCHAR#, #alamat:VARCHAR#)
    </insert>

    <select id="selectAllContoh" resultMap="result">
    select nama, alamat
    from contoh
    </select>

</sqlMap>

and ibatis’ main xml configuration, sqlmapconfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMapConfig
PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-config-2.dtd">

<sqlMapConfig>

    <settings
          cacheModelsEnabled="true"
          enhancementEnabled="true"
          lazyLoadingEnabled="true"
          maxRequests="128"
          maxSessions="24"
          maxTransactions="12"
          defaultStatementTimeout="60"
          useStatementNamespaces="true"
       />

    <sqlMap resource="com/edw/sqlmap/contoh.xml"/>

</sqlMapConfig>

because im using Spring, i need one main xml configuration for my Spring app, i named it spring.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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">


    <context:component-scan base-package="com.edw"/>
    <tx:annotation-driven transaction-manager="transactionManager"/>
    <context:annotation-config/>

    <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
        <property name="configLocation" value="com/edw/sqlmap/sqlmapconfig.xml"/>
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost/test"/>
        <property name="username" value="root"/>
        <property name="password" value="password"/>
    </bean>

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

</beans>

and 1 singleton class to load my configuration,

package com.edw.config;

/**
 *
 * @author edw
 */
import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ApplicationContextProvider {

    private Logger logger = Logger.getLogger(ApplicationContextProvider.class);
    private ApplicationContext applicationContext;
    private static final ApplicationContextProvider provider = new ApplicationContextProvider();

    private ApplicationContextProvider() throws ExceptionInInitializerError {
        try {
            this.applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        } catch (Throwable ex) {
            logger.error("Initial ApplicationContext creation failed -- " + ex.getMessage(), ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public synchronized static ApplicationContextProvider getInstance() throws ExceptionInInitializerError {
        return provider;
    }

    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
}

i create a DAO class, to connect to my ibatis layer,

package com.edw.dao;

import com.edw.bean.Contoh;
import com.ibatis.sqlmap.client.SqlMapClient;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;
import org.springframework.stereotype.Repository;

/**
 *
 * @author edw
 */
@Repository(value = "contohDao")
public class ContohDao extends SqlMapClientDaoSupport {

    // empty constructor
    public ContohDao() {       
    }
     
    // autowired constructor
    // i dont know why, but i cant autowired sqlMapClient directly
    // it will cause  java.lang.IllegalArgumentException: Property 'sqlMapClient' is required
    @Autowired
    public ContohDao(SqlMapClient sqlMapClient) {
        setSqlMapClient(sqlMapClient);
    }

    public void insert(Contoh contoh){
        getSqlMapClientTemplate().insert("contoh.insertContoh",contoh);
    }

    public List<Contoh> select(){
        return getSqlMapClientTemplate().queryForList("contoh.selectAllContoh");
    }
}

and my Service class, i use it to connect to my DAO layer,

package com.edw.service;

import com.edw.bean.Contoh;
import com.edw.dao.ContohDao;
import java.util.List;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

/**
 *
 * @author edw
 */
@Service("contohService")
public class ContohService  {

    @Autowired
    private ContohDao contohDao;
    
    private Logger logger = Logger.getLogger(ContohService.class);

    @Transactional(isolation=Isolation.SERIALIZABLE)
    public void insert(Contoh contoh) {
        logger.debug("begin insert at "+this.getClass().getName());
        contohDao.insert(contoh);
        logger.debug("end insert at "+this.getClass().getName());
    }

    public List<Contoh> select() {
        logger.debug("begin select at "+this.getClass().getName());
        List<Contoh> contohs = contohDao.select();
        logger.debug("end select at "+this.getClass().getName());
        return contohs;
    }    
}

please be careful with isolation level, from what i’ve read,

In a typical application, multiple transactions run concurrently, often working
with the same data to get their job done. Concurrency, while necessary, can lead
to the following problems:

  • Dirty read—Dirty reads occur when one transaction reads data that has been
    written but not yet committed by another transaction. If the changes are
    later rolled back, the data obtained by the first transaction will be invalid.
  • Nonrepeatable read—Nonrepeatable reads happen when a transaction performs
    the same query two or more times and each time the data is different.
    This is usually due to another concurrent transaction updating the data
    between the queries.
  • Phantom reads—Phantom reads are similar to nonrepeatable reads. These
    occur when a transaction (T1) reads several rows, and then a concurrent
    transaction (T2) inserts rows. Upon subsequent queries, the first transaction
    (T1) finds additional rows that were not there before.

That’s why, im using Isolation.SERIALIZABLE, because

ISOLATION_SERIALIZABLE
This fully ACID-compliant isolation level ensures that dirty
reads, nonrepeatable reads, and phantom reads are all
prevented. This is the slowest of all isolation levels
because it is typically accomplished by doing full table
locks on the tables involved in the transaction.

this is my UI

package com.edw.ui;

import com.edw.bean.Contoh;
import com.edw.config.ApplicationContextProvider;
import com.edw.service.ContohService;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;

/**
 *
 * @author edw
 */
public class MenuUtama extends JFrame implements ActionListener {

    private JTextField txtNama = new JTextField();
    private JTextField txtAlamat = new JTextField();
    private JButton cmdButton = new JButton("Save");
    private Logger logger = Logger.getLogger(MenuUtama.class);

    public MenuUtama() {
        setLayout(new GridLayout(3, 3));
        Container con = this.getContentPane();
        con.add(new JLabel("nama : "));
        con.add(txtNama);
        con.add(new JLabel("Alamat : "));
        con.add(txtAlamat);
        con.add(cmdButton);

        cmdButton.addActionListener(this);
    }

    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == cmdButton) {
            Contoh contoh = new Contoh();
            contoh.setNama(txtNama.getText());
            contoh.setAlamat(txtAlamat.getText());

            try {
                ApplicationContext ac = ApplicationContextProvider.getInstance().getApplicationContext();
                ContohService service = (ContohService) ac.getBean("contohService");
                service.insert(contoh);
                logger.debug("success");
            } catch (Exception ex) {
                logger.error(ex.getMessage(), ex);
            }
        }
    }

    public static void main(String[] args) {
        MenuUtama menuUtama = new MenuUtama();
        menuUtama.setVisible(true);
        menuUtama.setSize(300, 150);
        menuUtama.setLocationRelativeTo(null);
    }
}

this is my junit test case

package com.edw.test;

import com.edw.bean.Contoh;
import com.edw.config.ApplicationContextProvider;
import com.edw.service.ContohService;
import java.util.List;
import org.apache.log4j.Logger;
import org.junit.Test;
import org.springframework.context.ApplicationContext;


/**
 *
 * @author edw
 */
public class TestKoneksi {

    @Test
    public void testingMain(){

        Logger logger = Logger.getLogger(TestKoneksi.class);

        ApplicationContext ac = ApplicationContextProvider.getInstance().getApplicationContext();
        ContohService service = (ContohService)ac.getBean("contohService");
        List<Contoh> contohs = service.select();

        for (Contoh contoh : contohs) {
            logger.debug(contoh.getNama()+" - "+contoh.getAlamat());
        }

        Contoh contoh = new Contoh();
        contoh.setNama("Ngorroc");
        contoh.setAlamat("Morroc");
        service.insert(contoh);

    }
}

this is the appereance of my swing app
ibatis swing spring app

this is what written on my console

[SqlMapClientTemplate] DEBUG org.springframework.orm.ibatis.SqlMapClientTemplate:177 - Opened SqlMapSession [com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl@b05acd] for iBATIS operation
[Connection] DEBUG java.sql.Connection:27 - {conn-100000} Connection
[SqlMapClientTemplate] DEBUG org.springframework.orm.ibatis.SqlMapClientTemplate:194 - Obtained JDBC Connection [com.mysql.jdbc.JDBC4Connection@17ec9f7] for iBATIS operation
[Connection] DEBUG java.sql.Connection:27 - {conn-100000} Preparing Statement:      insert into contoh (nama, alamat)     values (?, ?)     
[PreparedStatement] DEBUG java.sql.PreparedStatement:27 - {pstm-100001} Executing Statement:      insert into contoh (nama, alamat)     values (?, ?)     
[PreparedStatement] DEBUG java.sql.PreparedStatement:27 - {pstm-100001} Parameters: [ibatisInsert, testing masuk Ibatis]
[PreparedStatement] DEBUG java.sql.PreparedStatement:27 - {pstm-100001} Types: [java.lang.String, java.lang.String]
[ContohService] DEBUG com.edw.service.ContohService:28 - end insert at com.edw.service.ContohService
[DataSourceTransactionManager] DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager:730 - Initiating transaction commit
[DataSourceTransactionManager] DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager:259 - Committing JDBC transaction on Connection [com.mysql.jdbc.JDBC4Connection@17ec9f7]
[DataSourceUtils] DEBUG org.springframework.jdbc.datasource.DataSourceUtils:193 - Resetting isolation level of JDBC Connection [com.mysql.jdbc.JDBC4Connection@17ec9f7] to 4
[DataSourceTransactionManager] DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager:314 - Releasing JDBC Connection [com.mysql.jdbc.JDBC4Connection@17ec9f7] after transaction
[DataSourceUtils] DEBUG org.springframework.jdbc.datasource.DataSourceUtils:312 - Returning JDBC Connection to DataSource
[MenuUtama] DEBUG com.edw.ui.MenuUtama:51 - success

my NB Project Structure and libraries that i used
Netbeans Project structure, libraries and stuffs

btw, i highly recommend these books to understand more about Spring and Ibatis framework.

  1. Manning Spring in Action 2nd Edition
  2. Manning Ibatis in Action

thank you, have fun and good luck.
:-[

Google+

How to Convert Java List or ArrayList into ResultSet

At this project i found an obstacle, which i need to convert a reporting module from fetching data from database into fetching data from Webservices. At first I think it was easy, I just fetch strings from Webservice, and put it in a bean or in a map and put it all in an ArrayList, just like JasperReport. But I forgot, this isn’t JasperReport I’m using, I’m using bloody hell CrystalReport. And my Crystal-Report-calling method only accepting ResultSet for parameter, so somehow I need to convert strings from webservice into ResultSet.

My idea is adding strings from webservices into an ArrayList<Object> and adding this ArrayList into ArrayList<ArrayList<Object>> and converting it into rows of ResultSet. And im using MockRunner library to help me. This is how I do it :

I create a class to convert a list into result set

package com.edw.rs;

import com.mockrunner.mock.jdbc.MockResultSet;
import java.sql.ResultSet;
import java.util.List;

/**
 *
 * @author edw
 */
public class MyResultSet {

    public ResultSet getResultSet(List<String> headers, List<List<Object>> data) throws Exception {

        // validation
        if (headers == null || data == null) {
            throw new Exception("null parameters");
        }

        if (headers.size() != data.size()) {
            throw new Exception("parameters size are not equals");
        }

        // create a mock result set
        MockResultSet mockResultSet = new MockResultSet("myResultSet");

        // add header
        for (String string : headers) {          
            mockResultSet.addColumn(string);
        }

        // add data
        for (List<Object> list : data) {
            mockResultSet.addRow(list);
        }

        return mockResultSet;
    }
}

and i tested it with my junit class

package com.edw.rs.test;

import com.edw.rs.MyResultSet;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import org.junit.Test;

/**
 *
 * @author edw
 */
public class MyResultSetTest {

    private Logger logger = Logger.getLogger(MyResultSetTest.class);

    public MyResultSetTest() {
    }

    @Test
    public void testMyResultSet() throws Exception {
        MyResultSet myResultSet = new MyResultSet();
        List<String> headers = new ArrayList<String>();
        headers.add("id");
        headers.add("name");
        headers.add("salary");
        headers.add("age");

        List<List<Object>> data = new ArrayList<List<Object>>();
        for (int i = 0; i < 4; i++) {
            List<Object> objects = new ArrayList<Object>();
            objects.add(new Integer(i));
            objects.add("name " + i);
            objects.add(new Double(i));
            objects.add(new Integer(20 + i));
            data.add(objects);
        }

        ResultSet rs = myResultSet.getResultSet(headers, data);
        while (rs.next()) {
            logger.debug(rs.getString("id"));
            logger.debug(rs.getString(2));
            logger.debug(rs.getDouble("salary"));
            logger.debug(rs.getInt(4));
            logger.debug("------------------------");
        }

    }
}

this is the result on my IDE console

2010-08-18 18:13:09,112 [MyResultSetTest] DEBUG com.edw.rs.test.MyResultSetTest:42 - 0
2010-08-18 18:13:09,131 [MyResultSetTest] DEBUG com.edw.rs.test.MyResultSetTest:43 - name 0
2010-08-18 18:13:09,132 [MyResultSetTest] DEBUG com.edw.rs.test.MyResultSetTest:44 - 0.0
2010-08-18 18:13:09,132 [MyResultSetTest] DEBUG com.edw.rs.test.MyResultSetTest:45 - 20
2010-08-18 18:13:09,133 [MyResultSetTest] DEBUG com.edw.rs.test.MyResultSetTest:46 - ------------------------
2010-08-18 18:13:09,133 [MyResultSetTest] DEBUG com.edw.rs.test.MyResultSetTest:42 - 1
2010-08-18 18:13:09,189 [MyResultSetTest] DEBUG com.edw.rs.test.MyResultSetTest:43 - name 1
2010-08-18 18:13:09,189 [MyResultSetTest] DEBUG com.edw.rs.test.MyResultSetTest:44 - 1.0
2010-08-18 18:13:09,189 [MyResultSetTest] DEBUG com.edw.rs.test.MyResultSetTest:45 - 21
2010-08-18 18:13:09,190 [MyResultSetTest] DEBUG com.edw.rs.test.MyResultSetTest:46 - ------------------------
2010-08-18 18:13:09,190 [MyResultSetTest] DEBUG com.edw.rs.test.MyResultSetTest:42 - 2
2010-08-18 18:13:09,191 [MyResultSetTest] DEBUG com.edw.rs.test.MyResultSetTest:43 - name 2
2010-08-18 18:13:09,218 [MyResultSetTest] DEBUG com.edw.rs.test.MyResultSetTest:44 - 2.0
2010-08-18 18:13:09,219 [MyResultSetTest] DEBUG com.edw.rs.test.MyResultSetTest:45 - 22
2010-08-18 18:13:09,219 [MyResultSetTest] DEBUG com.edw.rs.test.MyResultSetTest:46 - ------------------------
2010-08-18 18:13:09,219 [MyResultSetTest] DEBUG com.edw.rs.test.MyResultSetTest:42 - 3
2010-08-18 18:13:09,220 [MyResultSetTest] DEBUG com.edw.rs.test.MyResultSetTest:43 - name 3
2010-08-18 18:13:09,225 [MyResultSetTest] DEBUG com.edw.rs.test.MyResultSetTest:44 - 3.0
2010-08-18 18:13:09,226 [MyResultSetTest] DEBUG com.edw.rs.test.MyResultSetTest:45 - 23
2010-08-18 18:13:09,226 [MyResultSetTest] DEBUG com.edw.rs.test.MyResultSetTest:46 - ------------------------

this is my project structure, FYI im using Netbeans 6.9.
Netbeans 6.9 Project Structure

all i can say is, Thank You mockrunner, you saved my life.

Google+