Java RMI Database Application

20 Mar 2011 by

Java RMI Database Application

Java RMI Database Application

Java RMI has been introduced to reduce the complexity in developing protocol that relies on UDP and TCP. Java RMI provides a simpler mechanism to invoke method remote. Here I will discuss the development of Java RMI with database application. This sample application is layered into 3 tier: client, RMI server or middleware, and database.

Client is very thin and lightweight. Here client is only responsible for user interface while large business processes are handed over to RMI middleware. The middleware contains server objects distributed in registry service. The client will lookup the entire object from the registry service and invoke methods remotely. Database server stands on another layer that will be accessed by the data accessors in RMI middleware.

If you do not understand what Java RMI is, better to have a look on these articles:

The advantages and disadvantages will be discussed here:

Advantages

  • Fair security as the database is hidden from clients
  • Deployment, upgrading and maintenance are easy since the core of business process located in one server

Disadvantages

  • Single point of failure
  • Performance bottle neck if there are too many requests
  • Under saturated network condition, performance of Java RMI is poor compares to TCP and UDP

Example

This example, I demonstrate the CRUD (Create, Read, Update, Delete) operations related to province. The client has an ability to invoke save, update, delete, find methods in the RMI middleware. And RMI middleware conveys these operations to data accessors and eventually to database server.

The structure of the files.

Database

  • Microsoft Access (Province.mdb) that contains a table called Province. Province table has 3 attributes namely Id (integer), ShortName (text:3), Name (text:255).

Server

  • RMI
    • Province.java (entity class mapping to database)
    • IRemoteProvince.java (RMI application interface)
    • ProvinceObject.java (Province object to be distributed)
    • ProvinceServer.java (Server application)
  • Data Accessors
    • DBManager.java (manage connection to database)
    • ProvinceRepository.java (provide CRUD operations)

Client

  • Province.java (same as server)
  • IRemoteProvince.java (same as server)
  • ProvinceClient.java (client application calling RMI server)

The source code lists here.

Province.java

import java.io.*;

/**
 * Province class implements Serialable
 * to support mashalling
 *
 * @author http://lycog.com
 */
public class Province implements Serializable {

  private int id_;
  private String shortName_;
  private String name_;

  public Province() {
  }

  public Province(int id, String shortName, String name) {
    id_ = id;
    shortName_ = shortName;
    name_ = name;
  }

  public int getId() {
    return id_;
  }

  public void setId(int id) {
    id_ = id;
  }

  public String getShortName() {
    return shortName_;
  }

  public void setShortName(String shortName) {
    shortName_ = shortName;
  }

  public String getName() {
    return name_;
  }

  public void setName(String name) {
    name_ = name;
  }

  public String toString() {
    return id_ + " - " + shortName_ + " - " + name_;
  }
}

IRemoteProvince.java

import java.rmi.*;
import java.util.ArrayList;

/**
 * IRemoteProvince interface
 * @author http://lycog.com
 */
public interface IRemoteProvince extends Remote {
  public int save(Province p) throws RemoteException;
  public int update(Province p) throws RemoteException;
  public int delete(Province p) throws RemoteException;
  public void deleteAll() throws RemoteException;
  public ArrayList findAll() throws RemoteException;
  public ArrayList findByName(String criteria) throws RemoteException;
}

ProvinceObject.java

import java.rmi.server.*;
import java.rmi.*;
import java.util.ArrayList;

/**
 * Server object
 * @author http://lycog.com
 */
public class ProvinceObject extends UnicastRemoteObject
        implements IRemoteProvince {

  public ProvinceObject() throws RemoteException {
    super();
  }

  public int save(Province p) {
    try {
      System.out.println("Invoke save from " + getClientHost());
    } catch (ServerNotActiveException snae) {
      snae.printStackTrace();
    }
    return ProvinceRepository.save(p);
  }

  public int update(Province p) {
    try {
      System.out.println("Invoke update from " + getClientHost());
    } catch (ServerNotActiveException snae) {
      snae.printStackTrace();
    }
    return ProvinceRepository.update(p);
  }

  public int delete(Province p) {
    try {
      System.out.println("Invoke delete from " + getClientHost());
    } catch (ServerNotActiveException snae) {
      snae.printStackTrace();
    }
    return ProvinceRepository.delete(p);
  }

  public void deleteAll() {
    try {
      System.out.println("Invoke deleteAll from " + getClientHost());
    } catch (ServerNotActiveException snae) {
      snae.printStackTrace();
    }
    ProvinceRepository.deleteAll();
  }

  public ArrayList findAll() {
    try {
      System.out.println("Invoke findAll from " + getClientHost());
    } catch (ServerNotActiveException snae) {
      snae.printStackTrace();
    }
    return ProvinceRepository.findAll();
  }

  public ArrayList findByName(String criteria) {
    try {
      System.out.println("Invoke findByName from " + getClientHost());
    } catch (ServerNotActiveException snae) {
      snae.printStackTrace();
    }
    return ProvinceRepository.findByName(criteria);
  }
}

ProvinceServer.java

import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

/**
 * Server
 * @author http://lycog.com
 */
public class ProvinceServer {

  public static void main(String[] args) {
    try {
      //Create and get reference to rmi registry
      Registry registry = LocateRegistry.createRegistry(1099);

      //Instantiate server object
      ProvinceObject po = new ProvinceObject();

      //Register server object
      registry.rebind("Province", po);
      System.out.println("ProvinceServer is created!!!");
    } catch (Exception e) {
      System.out.println(e);
    }
  }
}

DBManager.java

import java.sql.*;

/**
 * DBManager: Singleton pattern
 *
 * @author http://lycog.com
 */
public final class DBManager {

  private static DBManager _instance = null;
  private Connection _con = null;

  public DBManager() {
    //Connect to Ms Access
    _con = getMsAccessConnection();
  }

  //Thread safe instatiate method
  public static synchronized DBManager getInstance() {
    if (_instance == null) {
      _instance = new DBManager();
    }
    return _instance;
  }

  public Connection getConnection() {
    return _con;
  }

  /**
   * Connection to SQLServer Database
   */
  private static Connection getSQLServerConnection() {
    Connection con = null;

    try {
      Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");

      String URL = "jdbc:sqlserver://localhost;databaseName=NID;user=sa;password=123;";
      con = DriverManager.getConnection(URL);
    } catch (Exception e) {
      System.out.println(e);
    }
    return con;
  }

  /**
   * Connection to MySQL Database
   */
  private static Connection getMySQLConnection() {
    Connection con = null;

    try {

      String strCon = "jdbc:mysql://127.0.0.1/test?user=rtuser&password=123";
      con = DriverManager.getConnection(strCon);
    } catch (SQLException se) {
      System.out.println(se);
    }
    return con;
  }

  /**
   * Connection to Microsoft Access
   */
  private static Connection getMsAccessConnection() {
    Connection con = null;
    try {
      Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

      //String filename = "D:/Working/DB/";
      String filename = "Province.mdb";
      String URL = "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb)};DBQ=";
      URL += filename + ";}";

      con = DriverManager.getConnection(URL);

    } catch (Exception se) {
      System.out.println(se);
    }

    return con;
  }
}

ProvinceRepository.java

import java.sql.*;
import java.util.*;

/**
 * ProvinceRepository: data accessor
 * @author http://lycog.com
 */
public class ProvinceRepository {

  public static int save(Province p) {
    int iRet = -1;
    try {
      Connection con = DBManager.getInstance().getConnection();
      String SQL = "INSERT INTO Province(Id, ShortName, Name) Values(?,?,?)";
      PreparedStatement pstmt = con.prepareStatement(SQL);
      pstmt.setInt(1, p.getId());
      pstmt.setString(2, p.getShortName());
      pstmt.setString(3, p.getName());

      iRet = pstmt.executeUpdate();

      pstmt.close();
    } catch (SQLException se) {
      System.out.println(se);
    }

    return iRet;
  }

  public static int update(Province p) {
    int iRet = -1;
    try {
      Connection con = DBManager.getInstance().getConnection();
      String SQL = "UPDATE Province SET ShortName=?, Name=? WHERE Id=?";
      PreparedStatement pstmt = con.prepareStatement(SQL);
      pstmt.setString(1, p.getShortName());
      pstmt.setString(2, p.getName());
      pstmt.setInt(3, p.getId());

      iRet = pstmt.executeUpdate();

      pstmt.close();
    } catch (SQLException se) {
      System.out.println(se);
    }

    return iRet;
  }

  public static int delete(Province p) {
    int iRet = -1;
    try {
      Connection con = DBManager.getInstance().getConnection();
      String SQL = "DELETE FROM Province WHERE Id=?";
      PreparedStatement pstmt = con.prepareStatement(SQL);
      pstmt.setInt(1, p.getId());

      iRet = pstmt.executeUpdate();

      pstmt.close();
    } catch (SQLException se) {
      System.out.println(se);
    }
    return iRet;
  }

  public static void deleteAll() {
    Connection con = DBManager.getInstance().getConnection();
    try {
      con.setAutoCommit(false);
      String SQL = "DELETE FROM Province";
      PreparedStatement pstmt = con.prepareStatement(SQL);

      pstmt.executeUpdate();
      con.commit();
    } catch (SQLException se) {
      try {
        con.rollback();
      } catch (SQLException ise) {
      }
    } finally {
      try {
        con.setAutoCommit(true);
      } catch (SQLException fse) {
      }
    }
  }

  public static ArrayList findAll() {
    ArrayList arr = new ArrayList();

    try {
      String QRY = "SELECT * FROM Province ORDER BY Id";
      Connection con = DBManager.getInstance().getConnection();
      Statement stmt = con.createStatement();
      ResultSet rs = stmt.executeQuery(QRY);

      while (rs.next()) {
        Province p = new Province();
        p.setId(rs.getInt("Id"));
        p.setShortName(rs.getString("ShortName"));
        p.setName(rs.getString("Name"));
        arr.add(p);
      }

      stmt.close();
    } catch (SQLException se) {
      System.out.println(se);
    }
    return arr;
  }

  public static ArrayList findByName(String name) {
    ArrayList arr = new ArrayList();

    try {
      String QRY = "SELECT * FROM Province WHERE name LIKE(?) ORDER BY id";
      Connection con = DBManager.getInstance().getConnection();
      PreparedStatement pstmt = con.prepareStatement(QRY);
      pstmt.setString(1, "%" + name + "%");
      ResultSet rs = pstmt.executeQuery();

      while (rs.next()) {
        Province p = new Province();
        p.setId(rs.getInt("Id"));
        p.setShortName(rs.getString("ShortName"));
        p.setName(rs.getString("Name"));
        arr.add(p);
      }

      pstmt.close();
    } catch (SQLException se) {
      System.out.println(se);
    }
    return arr;
  }
}

ProvinceClient.java

import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.ArrayList;

/**
 * ProvinceClient: client application
 * @author http://lycog.com
 */
public class ProvinceClient {

  public static void main(String[] args) {
    try {
      //Get reference to rmi registry server
      Registry registry = LocateRegistry.getRegistry("127.0.0.1");

      //Lookup server object
      IRemoteProvince rp = (IRemoteProvince) registry.lookup("Province");

      //Save province
      Province bmc = new Province(1, "BMC", "Banteay Meanchey");
      Province bat = new Province(2, "BAT", "Battambang");
      Province kpc = new Province(3, "KPC", "Kampong Cham");
      Province kch = new Province(4, "KCH", "Kampong Cang"); //wrong name
      Province ksp = new Province(5, "KSP", "Kampong Speu");

      //Save province
      System.out.println("Saving provinces...");
      rp.save(bmc);
      rp.save(bat);
      rp.save(kpc);
      rp.save(kch);
      rp.save(ksp);

      //Update province
      System.out.println("Update Kampong Cang to Kampong Chhang");
      Province updatedKCH = new Province(4, "KCH", "Kampong Chhnang");
      int iRet = rp.update(updatedKCH);

      //Display all provinces
      System.out.println("Display all provinces");
      ArrayList arrProv = rp.findAll();
      for (Province p : arrProv) {
        System.out.println(p.toString());
      }

      //Delete Kampong Cham
      System.out.println("Delete KPC");
      rp.delete(kpc);

      //Display province starts by "Kam"
      System.out.println("Display province starts by \"Kam\"");
      arrProv = rp.findByName("Kam");
      for (Province p : arrProv) {
        System.out.println(p.toString());
      }

      //Delete all provinces
      System.out.println("Delete all provinces");
      rp.deleteAll();

    } catch (Exception e) {
      System.out.println(e);
    }
  }
}

 

Tags: ,

21 responses so far

Leave a Reply