Archive for July, 2008

RMI magic in 5 minutes

26 July 2008

Nektarios, a great architect, says that RMI is “Magic Johnson” of Java!

Indeed, Remote Method Invocation is a robust base of hot technologies like EJB and Jini. So it’s there from a world-wide bank system to the networked refrigerators of the future.

Let’s build a service that is accessible from a client on another computer = another JVM.

For this we need the following,

On the server:

  • An interface with the desired methods that are available to all clients. Let’s call it ServerRemote.
  • A concrete class that implements the desired methods. Let’s call it Server.

On the client:

  • The client class that calls the remote methods. Let’s call it Client.

A simplified view follows.

Step 1: Define the interface

The interface is the key contract between the client and the server. The client knows about the behavior (methods) available on the server through this interface. That’s very important, because

  1. The client just needs to have an interface in its classpath. (lightweight)
  2. The server may freely update the concrete implementation without having to re-distribute it to the clients. (ease of development)

Our interface must extend java.rmi.Remote.

    public interface ServerRemote extends Remote {

    }

Also any behavior defined must throw a java.rmi.RemoteException.

    public interface ServerRemote extends Remote {

        public abstract String sayHello() throws RemoteException;

    }

Here’s all the code of the server’s interface.

    import java.rmi.Remote;
    import java.rmi.RemoteException;

    /**
     * This interface defines the methods that are publicly
     * available to the remote clients.
     */
    public interface ServerRemote extends Remote {

        public abstract String sayHello() throws RemoteException;

    }

Step 2: Develop the server class

The concrete class that implements the above interface must be a UnicastRemoteObject.

    public class Server extends UnicastRemoteObject implements ServerRemote {

    }

According to the API, UnicastRemoteObject’s no-argument constructor throws a RemoteException.

    public class Server extends UnicastRemoteObject implements ServerRemote {

        protected Server() throws RemoteException {
        }

    }

We should also implement the method sayHello() defined in the interface.

    public class Server extends UnicastRemoteObject implements ServerRemote {

        protected Server() throws RemoteException {
        }

        public String sayHello() throws RemoteException {

        }

    }

Let’s say it returns the string “Hello from RMI!!”. Here’s all the code of the server class.

    import java.rmi.Remote;
    import java.rmi.RemoteException;
    import java.rmi.server.UnicastRemoteObject;

    /**
     * This is the concrete implementation of the server.
     * It contains the actual implementation of all methods
     * that are available to the remote clients.
     */
    public class Server extends UnicastRemoteObject implements ServerRemote {

        protected Server() throws RemoteException {
        }

        public String sayHello() throws RemoteException {
            return "Hello from RMI!!";
        }

    }

Step 3: Deploy the server

Make a folder C:/server, copy Server.java and ServerRemote.java inside and compile them with the javac tool.

Now run the RMI compiler tool on the Server class.

This tool creates a helper class with the name Server_Stub.class.

It’s job is to handle all the communication between the client and the server. Please note that it must be in the classpath of both the client and the server.

Note: If you are using a JDK version prior to 1.6, a Server_Skeleton.class is also created. This file is on the server side only.

Now let’s initialize the RMI registry. Simply type rmiregistry on the command prompt.

So the RMI registry is up and running. Just leave this window open! We should now declare our service to the registry.

In the same folder make a simple class with just a main method.

    import java.rmi.Naming;

    /**
     * It simply declares (registers) our service to the RMI registry
     * using JNDI.
     */
    public class RunServer {

        public static void main(String[] args) throws Exception {
            Naming.rebind("MagicJohnson", new Server());
        }

    }

Open a different command-prompt window, compile the class and run it!

So at this point we have 2 open command-prompt windows: Our service (the first window) bounded to the RMI registry (the second window).

Step 4: Develop the client

Our service has the name “MagicJohnson”. The clients can use this name to lookup our service. It’s like opening a phone-book and searching for Mr. “MagicJohnson”.

The JNDI command to search the phone-book is really simple.

    Naming.lookup("rmi://serverAddress/serviceName");
  • rmi:// is the protocol.
  • serverAddress can be the IP address of the server (e.g. 127.0.0.1), it’s hostname on the local network (e.g. mycomputer) or a DNS name (e.g. www.myserver.com/rmi).
  • serviceName is the JNDI name of our service, in this case “MagicJohnson”.

Make a folder C:/client and place inside

  1. the interface (ServerRemote.class)
  2. the helper class (Server_Stub.class)
  3. and the following simple class
    import java.rmi.Naming;

    /**
     * It uses JNDI to find and call our service.
     */
    public class Client {

        public static void main(String[] args) throws Exception {
            ServerRemote remote = (ServerRemote)Naming.lookup("rmi://127.0.0.1/MagicJohnson");
            System.out.println(remote.sayHello());
        }

    }

Open a command-prompt window at the client folder, compile and run it!

To try this remotely, just take the folder to another computer on the network and change 127.0.0.1 with the actual IP of the computer that RMI registry is running!

Review

  • The service available to the clients is defined in an interface.
  • This interface IS-A Remote.
  • The actual implementation of the service IS-A UnicastRemoteObject.
  • RMI uses JNDI; directory functionality like a phonebook.

On the server we need

  1. the interface
  2. the actual service, a concrete class that implements the interface
  3. the stub (generated by the JDK)
  4. the skeleton (generated by earlier JDKs)

On the client we need

  1. the interface
  2. the stub class (from the server)
  3. a simple class that calls our service

Conclusion: Just like Magic Johnson makes great passes to the hoop, RMI serves excellent technologies like EJB and Jini.

Thank you.

JDBC dalam 10 menit

7 July 2008

Selamat datang saudara dari Indonesia. Pelajaran sederhana ini tentang JDBC dasar. Saudara akan membuat sebuah aplikasi Java yang bisa berkomunikasi dengan basis data.

Setiap metode yang pakai JDBC pasti ikut langkah yang berikut:

  • Langkah 1. Menyambungkan ke basis data.
  • Langkah 2. Bersiap sebuah perintah SQL.
  • Langkah 3. Bertanya perintah SQL dan mengambil hasilnya.
  • Langkah 4. Melepaskan sambungan.

Mari kita menyimpan orang-orang (persons) di basis data. Untuk setiap orang kita tertarik tentang 1. nama (name) 2. umur (age) dan 3. satu nomor yang unik (key).

  1. Instalasi MySQL
  2. Bangunan struktur basis data
  3. Memasukkan JDBC driver di classpath
  4. Bangunan kelas penyambung
  5. Bangunan model
  6. Memasukkan data (insert)
  7. Mengambil data (select)
  8. Mengubahkan data (update)
  9. Menhapus data (delete)
  10. Mencoba kalau semua sudah pas

Untuk aplikasi ini hanya tiga kelas harus dibuat: Connector kelas yang bisa menyambungkan ke basis data, Person kelas yang ada menggambarkan seorang dan PersonSQL kelas yang bisa memasukkan, mengubahkan, mengambil dan menghapus orang2 dari basis data itu.

1. Instalasi MySQL

Mendapatkan MySQL dari mysql.com → downloads → MySQL Community Server → Windows ZIP/Setup.EXE (x86) → Pick a mirror → No thanks, just take me to the downloads → Japan [JMPA] HTTP → mysql-5.0.51b-win32.zip

Mendapatkan JDBC driver MySQL (perhubungan antara Java dan MySQL, disebut driver atau connector dalam bahasa inggris) dari mysql.com → downloads → Connectors → Connector/J → Source and Binaries (zip) → Pick a mirror → No thanks, just take me to the downloads → Japan [JMPA] HTTP → mysql-connector-java-5.1.6.zip

MySQL dapat diinstal dengan mudah. Habis proses instalasi kotak dialog konfigurasi akan muncul. Pilih “Best Support For Multilingualism” dan tulis di kertas sandi administrator (root password).

Menaktifkan MySQL melalui Start → Programs → MySQL → MySQL Server 5.0 → MySQL Command Line Client → dan masukan sandi yang tadi.

2. Bangunan struktur basis data

Membuat sebuah struktur basis data di MySQL dengan create database hello;

Untuk memastikan ketiklah show databases; dan terus use hello;

Untuk membuat sebuah tabel di MySQL tulislah
CREATE TABLE persons (name VARCHAR(255), age SMALLINT, id BIGINT AUTO_INCREMENT, primary key (id));

Untuk memastikan ketik show tables; dan terus describe persons;

3. Memasukkan JDBC driver di classpath

Di dalam mysql-connector-java-5.1.6.zip ada mysql-connector-java-5.1.6-bin.jar. Ini cara untuk masukkan jar ini di classpath…

Kalau pakai Eclipse: Project → Java Build Path → Libraries → Add External JARs…

Kalau pakai Netbeans: File → “Project” Properties → Libraries → Add JAR/Folder

Kalau pakai JDeveloper 11g: Tools → Project Properties… → Libraries and Classpath → Add JAR/Directory…

4. Bangunan kelas penyambung

Kelas ini akan menyambung ke basis data dan akan melepaskan sambungan ini.

Pertama kita harus daftar JDBC driver,

     Class.forName("com.mysql.jdbc.Driver");

dan kasih tahu tentang nama user, sandi

     String username = "root";
     String password = "qweasdzxc";

dan url basis data,

     String url = "jdbc:mysql://127.0.0.1/hello";

Karena MySQL di komputer yang sama dengan aplikasi alamatnya 127.0.0.1. jdbc:mysql:// adalah protokol dan hello nama struktur basis data.

Inilah keseluruhan metode yang menyambungkan ke basis data.

public static Connection getConnection() throws Exception {
   Class.forName("com.mysql.jdbc.Driver");
   String username = "root";
   String password = "qweasdzxc";
   String url = "jdbc:mysql://127.0.0.1/hello";
   connection = DriverManager.getConnection(url, username, password);
   connection.setAutoCommit(false);
   return connection;
}

Inilah keseluruhan metode yang melepaskan sambungan dari basis data.

public static void closeConnection(PreparedStatement statement,
      ResultSet results, Connection connectionthrows Exception {
   if (statement != null) {
      statement.close();
      statement = null;
   }
   if (results != null) {
      results.close();
      results = null;
   }
   if (connection != null) {
      connection.close();
      connection = null;
   }
}

5. Bangunan model

Kelas ini menggambarkan seorang. Metodenya hanya get dan set (javabean).

public class Person implements Serializable {

   private String name;
   private int age;
   private int id;

   public int getAge() {
      return age;
   }

   public void setAge(int age) {
      this.age = age;
   }

   public int getId() {
      return id;
   }

   public void setId(int id) {
      this.id = id;
   }

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

}

6. Memasukkan data (insert)

Untuk memasukkan data mari kita ikut langkah yang empat:

Langkah 1. Menyambungkan ke basis data.

     Connector.getConnection();

Langkah 2. Bersiap sebuah perintah SQL.

     connection.prepareStatement("INSERT INTO persons(name, age) VALUES(?, ?)");
     statement.setString(1, person.getName());
     statement.setInt(2, person.getAge());

Langkah 3. Bertanya perintah SQL dan mengambil hasilnya.

     statement.executeUpdate();

Langkah 4. Melepaskan sambungan.

     Connector.closeConnection(...);

Mari kita lihat metode ini.

private Connection connection;
private PreparedStatement statement;

public boolean insert(Person personthrows Exception {
   boolean result = false;
   try {
      // step 1: connect to database
      connection = Connector.getConnection();
      // step 2: prepare the statement
      statement = connection.prepareStatement("INSERT INTO persons(name, age) VALUES(?, ?)");
      statement.setString(1, person.getName());

      statement.setInt(2, person.getAge());
      // step 3: execute the statement and get the results
      if (statement.executeUpdate() == 1) {
         result = true;
         connection.commit();
      }
   catch (Exception e) {
      connection.rollback();
      throw e;
   finally {
      // step 4: close the connection
      Connector.closeConnection(statement, null, connection);
   }
   return result;
}

7. Mengambil data (select)

Untuk mencari/mengambil data mari kita tetap ikut langkah yang empat:

Langkah 1. Menyambungkan ke basis data.

     Connector.getConnection();

Langkah 2. Bersiap sebuah perintah SQL.

     statement = connection.prepareStatement("SELECT * FROM persons WHERE id = ?");
     statement.setInt(1, id);

Langkah 3. Bertanya perintah SQL dan mengambil hasilnya.

     statement.executeQuery();

Langkah 4. Melepaskan sambungan.

     Connector.closeConnection();


public Person select(int idthrows Exception {
   Person person = null;
   try {
      // step 1: connect to database
      connection = Connector.getConnection();
      // step 2: prepare the statement and fill it
      statement = connection
            .prepareStatement("SELECT * FROM persons WHERE id = ?");
      statement.setInt(1, id);
      // step 3: execute and get the results
      set = statement.executeQuery();
      if (set.next()) {
         person = new Person();
         person.setName(set.getString("name"));
         person.setAge(set.getInt("age"));
         person.setId(set.getInt("id"));
      }
   finally {
      // step 4: close the connection
      Connector.closeConnection(statement, set, connection);
   }
   return person;
}

8. Mengubahkan data (update)

Untuk mengubah nilai data yang sudah tersimpan:

Langkah 1. Menyambungkan ke basis data.

     Connector.getConnection();

Langkah 2. Bersiap sebuah perintah SQL.

     statement = connection.prepareStatement("UPDATE persons SET name = ?, age = ? WHERE id = ?");
     statement.setString(1, person.getName());
     statement.setInt(2, person.getAge());
     statement.setInt(3, person.getId());

Langkah 3. Bertanya perintah SQL dan mengambil hasilnya.

     statement.executeUpdate();

Langkah 4. Melepaskan sambungan.

     Connector.closeConnection();


public boolean update(Person personthrows Exception {
   boolean result = false;
   try {
      // step 1: connect to database
      connection = Connector.getConnection();
      // step 2: prepare the statement and fill it
      statement = connection
            .prepareStatement("UPDATE persons SET name = ?, age = ? WHERE id = ?");
      statement.setString(1, person.getName());
      statement.setInt(2, person.getAge());
      statement.setInt(3, person.getId());
      // step 3: execute and get the results
      if (statement.executeUpdate() == 1) {
         result = true;
         connection.commit();
      }
   catch (Exception e) {
      connection.rollback();
      throw e;
   finally {
      // step 4: close the connection
      Connector.closeConnection(statement, null, connection);
   }
   return result;
}

9. Menhapus data (delete)

Langkah 1. Menyambungkan ke basis data.

     Connector.getConnection();

Langkah 2. Bersiap sebuah perintah SQL.

     statement = connection.prepareStatement("DELETE FROM persons WHERE id = ?");

Langkah 3. Bertanya perintah SQL dan mengambil hasilnya.

     statement.executeUpdate();

Langkah 4. Melepaskan sambungan.

     Connector.closeConnection();


public boolean delete(int idthrows Exception {
   boolean result = false;
   try {
      // step 1: connect to database
      connection = Connector.getConnection();
      // step 2: prepare the statement and fill it
      statement = connection
            .prepareStatement("DELETE FROM persons WHERE id = ?");
      statement.setInt(1, id);
      // step 3: execute and get the results
      if (statement.executeUpdate() == 1) {
         result = true;
         connection.commit();
      }
   catch (Exception e) {
      connection.rollback();
      throw e;
   finally {
      // step 4: close the connection
      Connector.closeConnection(statement, null, connection);
   }
   return result;
}

10. Mencoba kalau semua sudah pas

Pada saat ini saudara sudah membuat aplikasi yang bisa berkomunikasi dengan basis data. Tetapi mari kita berjaga2 dulu dan mencoba semua metode ini.

Misalnya, untuk mencoba metode insert kita bisa membuat seorang person dulu..

   Person person = new Person();
   person.setName("Al Pacino");
   person.setAge(68);

dan coba menyimpan di basis data.

   new PersonSQL().insert(person);

Untuk memastikan di MySQL command prompt SELECT * FROM persons;

Result of an SQL query

Kalau saudara punya waktu yang cukup silakan baca cara-cara Connection, Statement, PreparedStatement, ResultSet.

Sebelum selesai, saya ingin minta maaf karena bahasa Indonesia saya masih kurang. Kalau saudara ingin berkomunikasi mari meninggalkan pesan (comment) di bawa.

Terima kasih,
Nikos.