Membuat Aplikasi Database Tanpa Coding Dengan NetBeans

P.S.: Pada artikel ini, saya memakai database Oracle TimesTen, akan tetapi langkah yang sama juga dapat diterapkan pada database lainnya asalkan memilih driver JDBC yang tepat untuk database tersebut.

Saya akan mencoba membuat sebuah program Java sederhana yang mengakses dan melakukan query pada database TimesTen.   Saya akan memakai Java 7 di NetBeans 7.3.   Karena NetBeans menyediakan fitur GUI editor yang lumayan canggih, pada artikel ini saya akan menempuh cara ang drag-n-drop (di balik layar NetBeans tetap memakai JPA!).   Saya tidak perlu mengetik kode program, bahkan satu baris kode program pun tidak perlu.   Seorang teman saya sangat tergila-gila pada fasilitas GUI yang drag-n-drop di NetBeans, membuatnya enggan beralih ke IDE lain.   Saya secara pribadi tidak akan pernah 100% bergantung pada visual editor, karena biasanya akselerasi hanya terasa di awalnya tapi sering kali ribet di kemudian hari 😉   Tapi mungkin ini hanya masalah selera; produktifitas seorang developer akan tinggi bila ‘selera’-nya terpenuhi.

Saya akan mulai dengan membuat sebuah proyek baru.   Untuk itu, saya memilih menu File, New Project….   Pada dialog yang muncul, saya memilih Java, Java Application kemudian men-klik tombol Next.   Saya mengisi nama proyek dengan LatihanTimesTen, kemudian menghilangkan tanda centang pada Create Main Class.   Setelah itu saya menyelesaikan pembuatan proyek baru dengan men-klik tombol Finish.

Sama seperti database lainnya yang berbasis SQL, untuk mengakses TimesTen di Java harus melalui JDBC API.   Btw, JDBC adalah sebuah ukan merupakan sebuah singkatan.   Walaupun demikian, nama JDBC sepertinya agak mirip dengan ODBC (Open Database Connectivity) buatan Microsoft, bahkan sekilas terlihat ada persamaan diantara mereka.   Untuk memakai ODBC, dibutuhkan driver yang disediakan oleh pembuat database.   Begitu juga, untuk memakai JDBC dibutuhkan driver JDBC dalam bentuk file JAR yang disediakan oleh pembuat database.   Pada instalasi saya, lokasi driver ini terletak di C:\TimesTen\tt1122_32\lib.   Untuk Java 7, saya akan memakai file bernama ttjdbc7.jar.   Pada dasarnya file ttjdbc7.jar dan ttjdbc6.jar adalah file yang sama (duplikat)!

Saya akan memakai fasilitas GUI dari NetBeans untuk menjelajahi database.   Tapi sebelumnya saya memastikan terlebih dahulu bahwa TimesTen Data Manager sudah dijalankan.   Untuk itu, saya memberikan perintah ttDaemonAdmin -start. Bagi   yang tidak ingin memakai perintah Command Prompt bisa langsung memerika di Control Panel, Administrative Tools, Services.   Setelah itu, saya juga melakukan koneksi pertama kali ke database melalui ttIsql agar database di-load ke memori sehingga dapat dipakai oleh user lainnya.

Lalu, saya memilih menu Window, Services di NetBeans.   Pada Databases, saya men-klik kanan dan memilih New Connection… seperti yang terlihat pada gambar berikut ini:

Mendaftarkan koneksi baru

Mendaftarkan koneksi baru

Setelah itu, pada Driver, saya memilih New Driver….   Akan muncul dialog New JDBC Driver. Saya mengisinya seperti dengan yang terlihat pada gambar berikut ini:

Mendaftarkan driver JDBC baru

Mendaftarkan driver JDBC baru

Pastikan pada Driver Class, yang dipilih adalah com.timesten.jdbc.TimesTenDriver dan bukan com.timesten.jdbc.TimesTenClientDriver.   Hal ini karena saya melakukan direct connection, bukan client server.

Setelah itu, saya men-klik tombol OK.   Kemudian, saya men-klik tombol Next untuk melanjutkan ke tahap berikutnya.

Saya mengisi dialog Customize Connection seperti pada gambar berikut ini:

Menambahkan informasi koneksi

Menambahkan informasi koneksi

Setelah itu, saya men-klik tombol Next.   Saya membiarkan schema SOLID terpilih (sesuai dengan nama user yang saya berikan) dan langsung men-klik tombol Next.   Saya kemudian mengisi Input connection name dengan TimesTen Database LATIHAN (boleh di-isi dengan nama apa saja), kemudian men-klik tombol Finish.

NetBeans tidak dapat menampilkan daftar tabel untuk database TimesTen, tetapi ia tetap dapat membantu saya dalam mengerjakan perintah SQL.   Saya men-klik kanan nama koneksi TimesTen Database LATIHAN, kemudian memilih menu Execute Command….   Akan muncul sebuah editor baru dimana saya bisa mengerjakan perintah SQL untuk koneksi tersebut, seperti yang terlihat pada gambar berikut ini:

Mengerjakan SQL dari NetBeans

Mengerjakan SQL dari NetBeans

Ok, sekarang saya mendefinisikan sebuah koneksi database.   Saya dapat mulai membuat kode program tanpa perlu ‘mengetik‘ (baca: sihir).   Pada window Projects, saya men-klik kanan Source Packages, kemudian memilih New, JFrame Form… seperti yang diperlihatkan oleh gambar berikut ini:

Membuat JFrame baru

Membuat JFrame baru

Bila menu ini tidak terlihat, saya dapat mencarinya dengan memilih Other….

Pada dialog yang muncul, saya mengisi Class Name dengan ProdukView dan mengisi package dengan com.wordpress.thesolidsnake.view.   Setelah itu, saya men-klik tombol Finish.

Pada visual editor yang muncul, saya men-drag komponen Table ke layar utama seperti yang terlihat pada gambar berikut ini:

Menambahkan komponen tabel

Menambahkan komponen tabel

Kemudian, saya men-klik kanan pada komponen yang baru saja saya tambahkan dan memilih menu paling awal yaitu Table Contents….   Pada kotak dialog Customizer Dialog yang muncul, saya memilih Bound, kemudian men-klik tombol Import Data to Form… seperti yang diperlihatkan oleh gambar berikut ini:

Melakukan binding data dari database

Melakukan binding data dari database

Pada dialog Import Data To Form, saya memilih koneksi database dan tabel seperti yang terlihat pada gambar berikut ini (saya mengandaikan bahwa tabel PRODUK sudah dibuat sebelumnya):

Mengambil informasi dari database

Mengambil informasi dari database

Setelah itu, saya men-klik tombol OK.   NetBeans akan memunculkan pesan menunggu untuk proses importing….   Setelah selesai, Binding Source secara otomatis akan terisi dengan produkList.

Saya akan berpindah ke tab Columns untuk mendefinisikan kolom yang akan ditampilkan.   Saya menambahkan dua buah kolom untuk tabel tersebut, sesuai dengan kolom yang ada di database, seperti yang terlihat pada gambar berikut ini:

Menambahkan kolom untuk tabel

Menambahkan kolom untuk tabel

Setelah itu, saya men-klik tombol Close untuk menutup dialog.

Sekarang, saya akan menjalankan aplikasi dengan men-klik tombol Run Project (atau menekan F6).   Pada dialog Run Project yang muncul, saya memastikan bahwa com.wordpress.thesolidsnake.view.ProdukView terpilih sebagai main class, lalu men-klik tombol OK.   Tabel akan muncul terisi dengan data dari database, seperti yang diperlihatkan oleh gambar berikut ini:

Tampilan program saat dijalankan

Tampilan program saat dijalankan

Sesuai dengan janji saya, tidak ada satu barispun kode program yang saya ketik disini.   Tapi dibalik layar, NetBeans akan memakai JPA untuk mengakses database!   Yup, JPA seperti pada plugin simple-jpa yang saya buat untuk Griffon, bukan plain SQL di JDBC.   Dengan demikian, NetBeans juga menghasilkan kode program yang membuat dan memakai EntityManager.   Bukan hanya itu, NetBeans juga menghasilkan sebuah domain class (atau tepatnya JPA Entity) dengan nama Produk yang sudah lengkap dengan named query, seperti yang diperlihatkan pada gambar berikut ini:

JPA Entity bernama Produk yang dihasilkan NetBeans

JPA Entity bernama Produk yang dihasilkan NetBeans

Kode program yang dihasilkan oleh NetBeans memakai org.jdesktop.swingbinding.JTableBinding untuk melakukan binding. Sebagai perbandingan, pada simple-jpa, binding dilakukan melalui SwingBuilder (bawaan Groovy) dan GlazedLists.   Untuk menentukan ekspresi setiap kolom, NetBeans memakai Expression Language (seperti pada JSP dan JSF).   Sebagai perbandingan, pada simple-jpa, saya memakai Groovy template engine yang menerima seluruh ekspresi Groovy.

Iklan

Seberapa Jauh Bedanya Program Yang Multithreading?

Satu fitur dari bahasa Java yang sudah ada sejak awal adalah dukungan multi-threading atau concurrency.  Saya masih ingat saat pertama kali mengenal Java, saya sering diberitahu bahwa salah satu kelebihan Java dibanding C++ adalah dukungan concurrency-nya.  Salah satu buktinya adalah Java memiliki keyword synchronized yang dapat dipakai pada method atau blok kode program.  Selain itu, pada Java 5, terdapat Executor Framework untuk melakukan pooling thread yang berguna dalam meningkatkan kinerja concurrency.  Pada Java 7, Fork/Join Framework diperkenalkan untuk memaksimalkan kinerja concurrency pada prosesor multicore.

Concurrency menjadi semakin penting karena saat ini sudah semakin banyak komputer pengguna yang memiliki prosesor multicore.  Produsen prosesor sepertinya mengalami hambatan dalam meningkatkan clock rate CPU.  Sebagai gantinya, mereka menciptakan prosesor yang lebih ‘kencang’ dengan multicore.  Sebagai contoh, seri prosesor Intel Core i5 dan Intel Core i7 memiliki clock rate yang tidak jauh berbeda (maksimal 3.6 GHz), tetapi perbedaan signifikannya terletak pada jumlah core.   Sebagai contoh, Intel Core i5 2500K memiliki 4 core, sementara itu Intel Core i7 2600K yang dijual lebih mahal $101 juga memiliki 4 core tetapi disertai tambahan Intel Hyper-Threading Technology sehingga memiliki 8 virtual core.  Dari sisi clock rate sendiri, Intel Core i7 2600K  3.4 GHz hanya lebih cepat 100 MHz dibanding Intel Core i5 2500K 3.3 GHz.

Pertanyaannya adalah apakah memiliki 8 core selalu jauh lebih cepat dibanding 4 core?  Tidak juga.  Semua kembali lagi ke software yang dijalankan oleh CPU tersebut.  Bila program yang dijalankan hanya memakai 1 thread, maka tidak akan ada penambahan kinerja yang berarti.  Jadi, untuk mendukung prosesor multicore agar bisa bekerja semaksimal mungkin, developer aplikasi desktop harus membuat aplikasi multithreading.

Pada kesempatan ini saya akan mencoba membandingkan perbedaan kinerja antara kode program Java yang single thread dengan aplikasi yang multi thread. Kedua program akan melakukan hal yang sama, yaitu membaca isi dari seluruh tulisan dari blog ini dan menampilkan informasi jumlah kata yang ditemui.  Agar gampang, saya terlebih dahulu menyimpan isi blog ini dalam sebuah file (ukurannya 1.37 MB).

Ini adalah kode program SingleThread.java yang melakukan proses secara single thread:

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class SingleThread {
    public void proses() throws IOException {
        List<Hasilpencarian> listHasil = new ArrayList<>();
        List<String> listBaris = Files.readAllLines(
            Paths.get("C:\\data.txt"),
            Charset.defaultCharset());

        for (String baris: listBaris) {
            for (String kata: baris.split(" ")) {
                if (kata.trim().length()==0) break;
                kata = kata.toLowerCase();
                HasilPencarian hasilPencarian = new HasilPencarian(kata, 1);
                int index = listHasil.indexOf(hasilPencarian);
                if (index >= 0) {
                    listHasil.get(index).tambahJumlah(hasilPencarian);
                } else {
                    listHasil.add(hasilPencarian);
                }
            }
        }

        Collections.sort(listHasil, new Comparator<HasilPencarian>() {
            @Override
            public int compare(HasilPencarian o1, HasilPencarian o2) {
                return o2.getJumlah() - o1.getJumlah();
            }
        });

        for (HasilPencarian hasilPencarian: listHasil) {
            System.out.println(hasilPencarian);
        }

    }

    public static void main(String[] args) {
        try {
            new SingleThread().proses();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

Kode program tersebut membutuhkan sebuah class HasilPencarian.java yang isinya adalah:

import java.util.Objects;

public class HasilPencarian {

    private static final long serialVersionUID = 1L;

    private String kata;
    private Integer jumlah;

    public HasilPencarian(String kata, Integer jumlah) {
        this.kata = kata;
        this.jumlah = jumlah;
    }

    public String getKata() {
        return kata;
    }

    public void setKata(String kata) {
        this.kata = kata;
    }

    public Integer getJumlah() {
        return jumlah;
    }

    public void setJumlah(Integer jumlah) {
        this.jumlah = jumlah;
    }

    public void tambahJumlah(Integer jumlah) {
       this.jumlah+=jumlah;
    }

    public void tambahJumlah(HasilPencarian hasilLain) {
        if (!hasilLain.getKata().equals(getKata())) {
            throw new RuntimeException("Tidak dapat menjumlahkan kata yang berbeda!");
        }
        tambahJumlah(hasilLain.getJumlah());
    }

    @Override
    public int hashCode() {
        int hash = 5;
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final HasilPencarian other = (HasilPencarian) obj;
        if (!Objects.equals(this.kata, other.kata)) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return String.format("%s: %d", getKata(), getJumlah());
    }

}

Kode program SingleThread.java cukup sederhana dan mudah dimengerti.  Ia akan membaca baris dari file, kemudian memecah setiap baris menjadi kata, lalu menghitung jumlah kata yang unik.  Setelah selesai, ia akan mengurutkan berdasarkan jumlah kata terbanyak dan menampilkannya.  Contoh hasil akan terlihat seperti:

yang: 3448
di: 2071
saya: 1783
akan: 1645
dengan: 1513
untuk: 1496
pada: 1357
dan: 1268
adalah: 1057
seperti: 986
...

Terlihat bahwa selama ini kata yang paling sering saya tulis adalah ‘yang’ 🙂  Ok, tapi bukan itu tujuan saya.  Saya ingin memperlihatkan seperti apa kinerja program ini.  Untuk itu, saya akan melakukan profiling dengan menggunakan NetBeans Profiler.  Untuk itu, saya men-klik icon Profile Project yang terilhat seperti pada gambar berikut ini:

Icon ProfileProject Di NetBeans

Icon ProfileProject Di NetBeans

Saya kemudian memilih CPU, Analyze Performance, dan men-klik tombol Run.  Setelah proses profiling selesai, saya dapat melihat hasil snapshot seperti pada gambar berikut ini:

CPU Sampling Pada Aplikasi Versi Single Thread

CPU Sampling Pada Aplikasi Versi Single Thread

Terlihat bahwa dibutuhkan sekitar 24,6 detik untuk mengerjakan program ini (ini adalah penantian yang cukup lama!).  Waktu paling lama habis dipakai untuk mengerjakan method indexOf() milik ArrayList (karena berada dalam looping).

Saya kembali men-klik icon Profile Project.  Kali ini saya memilih Monitor, memberi tanda centang pada Enable threads monitoring dan Sample threads states.  Setelah men-klik Run dan membiarkan proses profiling selesai, saya dapat melihat daftar threads seperti yang terlihat di gambar berikut ini:

Tampilan Thread Pada Aplikasi Single Thread

Tampilan Thread Pada Aplikasi Single Thread

Disini terlihat bahwa thread pada aplikasi saya hanya satu, yaitu main.  Sisanya adalah thread milik JVM yang selalu ada, misalnya untuk keperluan garbage collector.

Sekarang, saya akan membuat program versi multithread yang memakai Fork/Join Framework dari Java 7.  Kode program ini tidak akan bisa dijalankan pada Java versi sebelumnya.

Saya akan membuat class MultiThread.java yang isinya adalah:

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.ForkJoinPool;

public class MultiThread {

    public void proses() throws IOException {

        List<String> listBaris = Files.readAllLines(
            Paths.get("C:\\data.txt"),
            Charset.defaultCharset());

        ForkJoinPool pool = new ForkJoinPool();

        TaskPemisah taskPemisah = new TaskPemisah(listBaris, 0, listBaris.size()-1);
        List<HasilPencarian> listHasil = pool.invoke(taskPemisah);

        Collections.sort(listHasil, new Comparator<HasilPencarian>() {
            @Override
            public int compare(HasilPencarian o1, HasilPencarian o2) {
                return o1.getKata().compareTo(o2.getKata());
            }
        });

        TaskPenghitung taskPenghitung = new TaskPenghitung(listHasil, 0, listHasil.size()-1);
        listHasil = pool.invoke(taskPenghitung);
        pool.shutdown();

        Collections.sort(listHasil, new Comparator<HasilPencarian>() {

            @Override
            public int compare(HasilPencarian o1, HasilPencarian o2) {
                return o2.getJumlah() - o1.getJumlah();
            }

        });

        for (HasilPencarian hasilPencarian: listHasil) {
            System.out.println(hasilPencarian);
        }

    }

    public static void main(String[] args) {
        try {
            new MultiThread().proses();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

}

Kode program MultiThread.java terlihat lebih rumit dibanding SingleThread.java.   Setelah setiap baris dibaca dari file, kode program tersebut akan memakai sebuah RecursiveTask untuk memisahkan setiap baris menjadi kata.  Setelah selesai, hasilnya akan diproses lagi oleh RecursiveTask lain yang menghitung jumlah kata. Karena prosesnya dilakukan secara concurrent, saya perlu mengurutkan kata berdasarkan abjad terlebih dahulu. Tujuannya adalah agar kata yang sama tidak diproses oleh thread yang berbeda (bila hal ini terjadi, hasil perhitungan akan salah!).

RecursiveTask pertama yang bertugas untuk memisahkan setiap baris menjadi kata akan saya beri nama sebagai TaskPemisah, isinya akan terlihat seperti berikut ini:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.RecursiveTask;

public class TaskPemisah extends RecursiveTask<List<HasilPencarian>> {

    private List<String> listBaris;
    private int indexMulai;
    private int indexSelesai;

    public TaskPemisah(List<String> listBaris, int indexMulai, int indexSelesai) {
        this.listBaris = listBaris;
        this.indexMulai = indexMulai;
        this.indexSelesai = indexSelesai;
    }

    @Override
    protected List<HasilPencarian> compute() {
        List<HasilPencarian> listHasil = new ArrayList<>();
        if ((indexSelesai - indexMulai) < 10) {
            for (int i=indexMulai; i<=indexSelesai; i++) {
                String baris = listBaris.get(i);
                for (String kata: baris.split(" ")) {
                    if (kata.trim().length()==0) break;
                    kata = kata.trim().toLowerCase();
                    HasilPencarian hasilPencarian = new HasilPencarian(kata, 1);
                    listHasil.add(hasilPencarian);
                }
            }
        } else {
            int indexTengah = (indexSelesai + indexMulai) / 2;
            TaskPemisah task1 = new TaskPemisah(listBaris, indexMulai, indexTengah);
            TaskPemisah task2 = new TaskPemisah(listBaris, indexTengah+1, indexSelesai);
            invokeAll(task1, task2);
            try {
                listHasil.addAll(task1.get());
                listHasil.addAll(task2.get());
            } catch (InterruptedException | ExecutionException ex) {
                ex.printStackTrace();
            }
        }
        return listHasil;
    }

}

RecursiveTask yang akan menghitung jumlah kata akan saya beri nama sebagai TaskPenghitung, isinya akan terlihat seperti berikut ini:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.RecursiveTask;

public class TaskPenghitung extends RecursiveTask<List<HasilPencarian>>{

    private List<HasilPencarian> listProses;
    private int indexMulai;
    private int indexSelesai;

    public TaskPenghitung(List<HasilPencarian> listProses, int indexMulai, int indexSelesai) {
        this.listProses = listProses;
        this.indexMulai = indexMulai;
        this.indexSelesai = indexSelesai;
    }

    private void proses(List<HasilPencarian> listHasil) {
        for (int i=indexMulai; i<=indexSelesai; i++) {
            HasilPencarian hasilPencarian = listProses.get(i);
            int index = listHasil.indexOf(hasilPencarian);
            if (index >= 0) {
                listHasil.get(index).tambahJumlah(hasilPencarian);
            } else {
                listHasil.add(hasilPencarian);
            }
        }
    }

    @Override
    protected List<HasilPencarian> compute() {
        List<HasilPencarian> listHasil = new ArrayList<>();
        if ((indexSelesai - indexMulai) < 1000) {
            proses(listHasil);
        } else {
            int tengah = (indexMulai + indexSelesai) / 2;
            while (true) {
                if (tengah==indexSelesai) {
                    proses(listHasil);
                    return listHasil;
                }
                String kataSekarang = listProses.get(tengah).getKata();
                String kataBerikut = listProses.get(tengah+1).getKata();
                if (!kataSekarang.equals(kataBerikut)) break;
                tengah++;
            }

            TaskPenghitung task1 = new TaskPenghitung(listProses, indexMulai, tengah);
            invokeAll(task1);

            TaskPenghitung task2 = null;
            if (tengah<indexSelesai) {
                task2 = new TaskPenghitung(listProses, tengah+1, indexSelesai);
                invokeAll(task2);
            }

            try {
                listHasil.addAll(task1.get());
                if (task2!=null) {
                    listHasil.addAll(task2.get());
                }
            } catch (InterruptedException | ExecutionException ex) {
                ex.printStackTrace();
            }
        }
        return listHasil;
    }

}

Bila dijalankan, hasilnya akan sama persis seperti pada versi SingleThread.java.  Yang jelas, kode program MultiThread.java lebih panjang, lebih rumit, dan jumlah class-nya tambah banyak.  Apakah kerumitan ini memiliki manfaat?

Saya akan mulai dengan melakukan profiling kinerja.  Hasil CPU sampling dapat dilihat pada gambar berikut ini:

CPU Sampling Pada Aplikasi Versi Multi Thread

CPU Sampling Pada Aplikasi Versi Multi Thread

Terlihat bahwa waktu yang dibutuhkan oleh MultiThread.java hanya 7,1 detik;  bandingkan dengan SingleThread.java yang membutuhkan 24,6 detik.   Peningkatan yang terjadi mencapai 71 %.  Ini adalah sebuah selisih yang cukup jauh.

Untuk membuktikan bahwa ini adalah aplikasi multithreading, saya akan melakukan profiling untuk me-monitor thread, dimana hasilnya akan terlihat seperti pada gambar berikut ini:

Tampilan Thread Pada Aplikasi Multi Thread

Tampilan Thread Pada Aplikasi Multi Thread

Pada gambar di atas, selain terdapat thread untuk main, juga ada thread ForkJoinPool-1-worker-1 dan ForkJoinPool-1-worker-1 (terlihat bahwa kode program belum maksimal karena masih sedikit yang ‘hijau’ secara bersamaan!).  Mereka diciptakan oleh class ForkJoinPool yang dipakai di MultiThread.java.   Secara default, jumlah thread yang diciptakan berdasarkan jumlah core CPU (prosesor) yang terdeteksi (pada prosesor yang memakai Hyper-Threading Technology, yang dipakai adalah jumlah virtual core).   Developer dapat menentukan nilai yang berbeda dengan melewatkan sebuah angka yang mewakili jumlah thread yang akan dibuat (nilai parallelism) di constructor ForkJoinPool.

Mengakses Web Services Dari Aplikasi Java Micro Edition (Mobile)

Artikel ini adalah request dari Erna

Seorang mahasiswi bertanya bagaimana cara mengakses database yang ada di server melalui aplikasi Java Micro Edition (JME) di ponsel.  Salah satu cara yang dapat ditempuh adalah dengan menggunakan web services.  Pada tulisan ini, saya akan memakai WS-* Web Services.  Alternatif lain adalah memakai web service RESTfulyang lebih ringan.

Membuat Web Service dengan Java Di Sisi Server

Web Service akan dijalankan pada komputer server yang terhubung dengan database.   Saya akan menggunakan NetBeans IDE. Langkah pertama adalah memilih menu File, New Project…  Kemudian pilih Java Web, Web Application.  Klik tombol Next. Berikan sebuah nama proyek seperti LatihanWebService, kemudian klik tombol Next.

Pada langkah berikutnya, saya memakai server GlassFish Server 3.1.2 dan versi Java EE 6 Web.  Saya membiarkan context path saya berupa /LatihanWebService.  Karena saya tidak akan memakai framework, maka saya langsung men-klik tombol Finish.

Klik kanan pada nama proyek, kemudian pilih New, Web Service…  Pada Web Service Name, isi dengan AksesDatabase.  Kemudian pada package, isi dengan co.id.jocki.webservice.  Kemudian klik tombol Finish.

Pada nama proyek, akan ada folder Web Services yang didalamnya terdapat node AksesDatabase.  Klik kanan pada AksesDatabase, kemudian pilih Add Operation…  Isi Name dengan lihatIsiTabel, dan isi Return Type dengan java.util.ArrayList<String>.  Klik tombol OK.

Saya akan menambah sebuah operasi lagi.  Untuk itu, saya kembali men-klik kanan pada AksesDatabase, kemudian saya memilih Add Operation…  Kali ini saya mengisi dialog yang muncul sehingga terlihat seperti berikut ini:

Membuat operasi Web Service

Membuat operasi Web Service

Klik tombol OK untuk menutup dialog.

Karena saya akan memakai database MySQL, saya perlu menambahkan MySQL connector terlebih dahulu.  Saya men-klik kanan pada nama proyek (LatihanWebService), lalu memilih Properties.  Kemudian saya memilih Libraries, Add Library…  Pada pilihan yang muncul, saya memilih MySQL JDBC Driver, kemudian saya men-klik tombol Add Library.  Klik tombol OK untuk menutup dialog.

Jika saya men-double klik pada AksesDatabase di Projects, NetBeans akan memunculkan kode program dimana saya bisa menuliskan implementasi.  Saya akan memakai kode program Java 7, sehingga untuk menjalankan program ini dibutuhkan Java JDK minimal versi 7.  Java versi terbaru dapat di-download di http://www.oracle.com/technetwork/java/javase/downloads/index.html.  Selain itu, saya men-klik kanan nama proyek, memilih Properties.  Pada Sources, saya memastikan bahwa JDK 7 sedang dipilih di bagian Source/Binary Format.

Berikut ini adalah isi file AksesDatabase.javayang telah saya modifikasi:

package co.id.jocki.webservice;
import com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource;
import java.sql.*;
import java.util.ArrayList;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;

@WebService(serviceName = "AksesDatabase")
public class AksesDatabase {
  private MysqlConnectionPoolDataSource dataSource;

  public AksesDatabase() {
    dataSource = new MysqlConnectionPoolDataSource();
    dataSource.setUser("jocki");
    dataSource.setPassword("password");
    dataSource.setURL("jdbc:mysql://localhost:3306/latihan"); 
  }

  private void buatTabelBilaBelumAda(Connection cn) throws SQLException {
    ResultSet rs = cn.getMetaData().getTables(null, null, "namatabel", null);
    if (rs.next()==false) {
      // Tidak ada tabel dengan nama 'namatabel', maka buat tabel tersebut
      cn.createStatement().execute("CREATE TABLE namatabel (data VARCHAR(255))");
    }
  }
  @WebMethod(operationName = "lihatIsiTabel")
  public ArrayList<String> lihatIsiTabel() {
    ArrayList<String> lstReturn = new ArrayList<>(); 
    try (Connection cn = dataSource.getConnection()) {
      buatTabelBilaBelumAda(cn);
      Statement stmt = cn.createStatement();
      ResultSet rs = stmt.executeQuery("SELECT data FROM namatabel");
      while (rs.next()) {
        lstReturn.add(rs.getString("data"));
      }
    } catch (Exception ex) {
      System.out.println("Kesalahan [" + ex.getMessage() + "]");
    } 
    return lstReturn;
  }
  @WebMethod(operationName = "tambah")
  public boolean tambah(@WebParam(name = "nilai") String nilai) { 
    try (Connection cn = dataSource.getConnection()) {
      buatTabelBilaBelumAda(cn);
      PreparedStatement ps = cn.prepareStatement("INSERT INTO namatabel VALUES (?)");
      ps.setString(1, nilai);
      ps.executeUpdate();
    } catch (Exception ex) {
      System.out.println("Kesalahan [" + ex.getMessage() + "]");
      return false;
    }
    return true;
  }
}

Pada kode program di atas, saya mengandaikan bahwa nama user MySQL adalah jocki dan password-nya adalah password.  Bila di database tidak ada user lain, bisa juga menggunakan nama user root dan password dikosongkan (“” / string kosong).   Saya juga mengandaikan nama database yang diakses adalah latihan (ini harus sesuai dengan nama database yang ada di MySQL).

Jalankan web services dengan men-klik kanan pada nama proyek LatihanWebService kemudian memilih menu Run.  Jangan matikan server ini karena nanti akan dipanggil oleh aplikasi JME.

Untuk informasi lebih lanjut mengenai bagaimana cara membuat web services atau ingin membuat implementasi web services dalam bahasa lain, baca artikel yang saya tulis di https://thesolidsnake.wordpress.com/2012/07/04/membuat-web-service-soap-dengan-php-dan-memanggilnya-di-client-java/ , https://thesolidsnake.wordpress.com/2012/05/26/memanggil-web-service-dari-server-java-ee-di-client-php/, atau https://thesolidsnake.wordpress.com/2012/07/08/perbandingan-web-service-soap-antara-java-ee-vs-php/ .

Membuat Aplikasi JME Sebagai Client

Saya akan membuat sebuah aplikasi JME dengan memilih menu File, New Project…  Lalu memilih Java ME, Mobile Application.  Pada Project Name, saya memberi nama LatihanClient.  Saya menghilangkan tanda centang di bagian Create Hello Midlet.  Kemudian saya men-klik tombol Next.  Pada Emulator Platform, saya akan memiliki CLDC Oracle Java(TM) Platform Micro Edition SDK 3.0.5.  Lalu pada Device, saya memilih DefaultCldcMsaPhone1.   Saya memastikan Device Configuration bernilai CLDC-1.1 dan Device Profile bernilai MIDP-2.1.  Kemudian saya men-klik Finish untuk membuat proyek tersebut.

Saya membuat sebuah MIDlet baru dengan men-klik kanan pada nama proyek, kemudian memilih New, MIDlet…  Pada MIDlet Name, saya mengisi LatihanMidlet.  Pada Package, saya mengisi co.id.jocki.midlet.  Lalu saya men-klik tombol Finish.

Langkah berikutnya adalah membuat stub untuk web services.  Saya mulai dengan men-klik kanan pada nama proyek, memilih New, Others…  Pada MIDP, saya memilih Java ME Web Service Client dan men-klik tombol Next. Pada langkah Java ME Web Service Client Information, pilih Running Web Service,  isi WSDL URL dengan http://localhost:8080/LatihanWebService/AksesDatabase.    Ini adalah URL web service yang telah saya buat sebelumnya.  Lalu klik tombol Retrieve WSDL.  Jika tidak terjadi kesalahan, NetBeans akan mengisi field yang ada secara otomatis seperti yang terlihat pada gambar berikut ini:

Menambah Stub WS ke Java ME

Menambah Stub WS ke Java ME

Klik tombol Finish untuk selesai.

Sekarang, di proyek JME LatihanClient, akan ada package AksesDatabase yang dibuat secara otomatis.  Yang perlu saya lakukan sekarang adalah menambahkan kode program pada LatihanMiddlet.java yang akan memakai stub tersebut untuk mengakses web services.

Berikut ini adalah isi LatihanMiddlet.javayang telah saya modifikasi:

package co.id.jocki.midlet;

import aksesdatabase.AksesDatabase;
import aksesdatabase.AksesDatabase_Stub;
import java.rmi.RemoteException;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.MIDlet;

public class LatihanMidlet extends MIDlet {

    private List listData;
    private Form frmTambah;
    private TextField txtData;
    private Command cmdSimpan;
    private Command cmdTambah;

    public void startApp() {
        if (listData==null) {            
            listData = new List("Data Di Database", List.EXCLUSIVE);            
            cmdTambah = new Command("Tambah", Command.ITEM, 0);            
            listData.addCommand(cmdTambah);
            listData.setCommandListener(new CommandListener() {

                public void commandAction(Command c, Displayable d) {
                    if (c==cmdTambah) {
                        Display.getDisplay(LatihanMidlet.this).setCurrent(frmTambah);
                    }
                }

            });

            frmTambah = new Form("Akses Database");
            txtData = new TextField("Data", null, 20, TextField.ANY);
            frmTambah.append(txtData);
            cmdSimpan = new Command("Simpan", Command.OK, 0);
            frmTambah.addCommand(cmdSimpan);
            frmTambah.setCommandListener(new CommandListener() {

                public void commandAction(Command c, Displayable d) {
                    if (c==cmdSimpan) {
                        String data = txtData.getString();
                        simpanDataKeDatabase(data);
                        getDataDariDatabase();
                        Display.getDisplay(LatihanMidlet.this).setCurrent(listData);
                    }
                }

            });

        }
        getDataDariDatabase();
        Display.getDisplay(this).setCurrent(listData);
    }        

    private void getDataDariDatabase() {
        AksesDatabase aksesDatabase = new AksesDatabase_Stub();
        listData.deleteAll();
        try {
            String[] data = aksesDatabase.lihatIsiTabel();
            for (int i=0; i<data.length; i++) {
                listData.append(data[i], null);
            }
        } catch (RemoteException ex) {            
            listData.append("Kesalahan Akses Data [" + ex.getMessage() + "]", null);
        }
    }

    private void simpanDataKeDatabase(String data) {
        AksesDatabase aksesDatabase = new AksesDatabase_Stub();
        try {
            aksesDatabase.tambah(data);
        } catch (RemoteException ex) {
            listData.append("Kesalahan Simpan Data [" + ex.getMessage() + "]", null);
        }
    }

    public void pauseApp() {
    }

    public void destroyApp(boolean unconditional) {
    }
}

Sekarang, saya akan mencoba menjalankan aplikasi JME tersebut dengan men-klik icon Run (F6).  Tampilan awal adalah sebuah List yang harusnya berisi isi tabel (saat ini masih kosong karena belum ada data):

Tampilan Awal (Isi Tabel Masih Kosong)

Tampilan Awal (Isi Tabel Masih Kosong)

Pilih menu “Tambah” (dengan left soft key/tombol untuk menu kiri).  Akan muncul frmTambah yang berisi sebuah TextField.  Saya mengisi TextField ini dengan jocki, kemudian memilih menuSimpan:

Menambah Data Baru

Menambah Data Baru

Hal ini akan menyebabkan nilai “jocki” disimpan di tabel database.   Sekarang saat List mengambil data dari tabel di database, ia akan menemukan sebuah data:

Data Diambil Dari Database

Data Diambil Dari Database

Seandainya saya menambah sebuah data baru dengan nilai “keren”, isi List akan terlihat seperti:

Mengambil Data Dari Database

Mengambil Data Dari Database

Bila ingin lebih yakin lagi, silahkan periksa isi tabel di database dan pastikan terdapat dua record dengan nilai “jocki” dan “keren”.

Memanggil web service dari server Java EE di client PHP

Seorang mahasiswa yang sedang membuat skripsi bertanya apakah mungkin membuat sebuah web service dengan Java Enterprise Edition kemudian memanggilnya di client PHP?  Pada kesempatan tatap muka yang singkat, saya menjawab secara ringkas dengan merujuk pada definisi web services. Web services adalah sistem yang dirancang secara khusus untuk mendukung interaksi pertukaran data mesin ke mesin melalui jaringan. Selama berkomunikasi melalui metode yang sama, maka proses komunikasi dapat terjadi tanpa membedakan OS maupun bahasa pemograman yang dipakai.   Saat ini ada dua jenis web services, yaitu yang berbasis REST dan berbasis SOAP. Web services berbasis REST cenderung lebih ringan dan lebih mudah dipelajari dibandingkan dengan SOAP. Hal ini menyebabkan terjadinya peralihan dari web services berbasis SOAP ke REST.

Pada kesempatan tertulis ini, saya akan memberikan sebuah contoh halaman PHP yang memanggil web services yang dibuat dengan Java Enterprise Edition. Metode yang dipergunakan adalah metode berbasis SOAP.

Saya akan membuat dua proyek, yaitu:

  1. Server web service yang menggunakan teknologi Java Enterprise Edition. Saya menggunakan NetBeans IDE dan GlassFish bawaannya.
  2. Sebuah halaman PHP yang mengakses layanan web service yang disediakan oleh server di atas.

Membuat Server Web Service dengan Java EE

Langkah-langkah yang saya lakukan adalah:

  1. Memilih menu File, New Project di NetBeans IDE. Kemudian saya memilih Java Web di Categories, dan Web Application di Projects. Setelah memberi nama proyek dan menentukan lokasi penyimpanan, saya men-klik tombol Finish.
  2. Men-klik kanan nama proyek, kemudian memilih menu New, Other... Pada dialog yang muncul, saya memilih Web Services di bagian Categories, dan Web Service di bagian File Typesseperti yang terlihat di gambar berikut ini:

    Membuat Web Services Baru

    Membuat Web Services Baru

  3.  Pada Web Service Name, saya mengisi dengan nama PerhitunganWS. Pada bagian package, saya mengisi dengan nama package co.id.jocki.ws. Setelah itu, saya men-klik tombol Finish.

NetBeans akan membuat sebuah class baru yang berada di folder Web Services seperti yang terlihat pada gambar berikut ini:

Web Services Di Tampilan Project

Web Services Di Tampilan Project

Bila class PerhitunganWS di-buka, NetBeans memungkinkan pengguna untuk melihat dalam bentuk Source atau Design. Bila tampilan Design dipakai, maka layar editor akan terlihat seperti pada gambar berikut ini:

NetBeans Web Service Editor

NetBeans Web Service Editor

Untuk menambahkan sebuah operasi baru, saya melakukan langkah-langkah seperti berikut ini:

  1. Klik tombol Add Operation… Akan muncul sebuah dialog baru.
  2. Untuk menambah parameter, saya dapat men-klik tombol Add. Saya mengisi dialog tersebut seperti yang terlihat pada gambar berikut ini:

    Menambah Operasi Baru Di Web Service

    Menambah Operasi Baru Di Web Service

  3. Setelah itu, saya men-klik tombol OK.

Setelah ini, saya perlu menambahkan kode program yang berisi proses untuk operasi baru tersebut.   Saya men-klik Source di toolbar untuk beralih ke tampilan kode program.   Kemudian, saya mengubah satu-satunya baris di method tambah() menjadi return angka1 + angka2; seperti yang terlihat di gambar berikut ini:

Kode Program Operasi Di Web Service

Kode Program Operasi Di Web Service

Untuk menguji web service tersebut, klik kanan pada nama class PerhitunganWS, kemudian memilih Test Web Service seperti yang terlihat di gambar berikut ini:

Menguji Web Services

Menguji Web Service

NetBeans akan menjalankan browser yang berisi web service tester. Di halaman ini terdapat sebuah link bertuliskan WSDL File. URL disini nantinya akan dipakai oleh client web service. Di percobaan saya, nilai URL ini adalah http://localhost:8080/ServerWebService/PerhitunganWS?WSDL. Saya akan men-copy lokasi URL ini untuk dipakai di PHP nantinya.

Pada bagian methods, saya mencoba mengisi parameter dengan nilai 10 dan 20, kemudian setelah men-klik tombol tambah (nama method), akan muncul halaman tambah Method invocation. Pastikan pada halaman tersebut, terdapat tulisan Method returned int: “30”.

Sekarang server web service telah selesai dibuat. Saya tidak mematikan GlassFish server di NetBeans karena pada langkah berikutnya, saya akan memanggil web service ini di PHP.

Membuat Client Web Service dengan PHP

Sebelum mulai membuat client web service di PHP, saya memastikan apakah extension SOAP telah diaktifkan di PHP saya. Yang saya lakukan adalah membuat sebuah file PHP dengan nama info.php dimana isinya adalah <?php phpinfo(); ?>. Saat menampilkan halaman tersebut di browser, saya memastikan bahwa terdapat baris Soap Client dengan nilai Enabled.

Untuk membuat client web service, saya perlu membuat sebuah object dari class SoapClient seperti pada baris berikut ini:

$client = new SoapClient("http://localhost:8080/ServerWebService/PerhitunganWS?WSDL");

Nilai dari parameter constructur SoapClient adalah URL yang merujuk ke lokasi file WSDL. URL ini dapat dilihat di halaman web service tester pada saat saya menguji server web service di NetBeans.

Secara utuh, kode program PHP yang saya buat adalah:

<?php
function errorHandler($errno, $errstr, $errfile, $errline, array $errcontext) {
print "<h3>Terjadi kesalahan/peringatan:</h3>";
print "Baris $errline [$errstr]";
exit;
}

set_error_handler('errorHandler');

$client = new SoapClient("http://localhost:8080/ServerWebService/PerhitunganWS?WSDL");
$daftarOperasi = $client->__getFunctions();
print "<h3>Daftar Operasi Yang Tersedia Di Server WS:</h3>";
foreach ($daftarOperasi as $operasi) {
print "<p>$operasi</p>";
}
$hasil = $client->tambah(array('angka1'=>20, 'angka2'=>10));
print "<h3>Hasil operasi hitung(10,20): " . $hasil->return . "</h3>";
?>

<!--?php 

Pada kode program tersebut, saya menyertakan pemeriksaan kesalahan dengan set_error_handler(). Bagian tersebut dapat digantikan dengan menggunakan try/catch. Akan tetapi bila menggunakan try/catch, hanya pesan kesalahan yang ditampilkan, sementara pesan warning tidak akan ditampilkan. Bila pengaturan penampilan pesan kesalahan & warning secara otomatis tidak dimatikan (nilai display_errors di file konfigurasi adalah stdout), maka bagian ini tidak diperlukan.

Karena server web service di GlassFish menyediakan file WSDL, maka saya dapat menggunakan method __getFunctions() untuk melihat operasi apa saja yang disediakan oleh server web service tersebut.

Untuk memanggil salah satu operasi yang ada, saya cukup memanggil method dengan nama yang bersesuaian, diikuti dengan parameter yang diletakkan dalam associative array. Sebagai contoh, di kode program di atas, saya memanggil operasi tambah dengan nilai parameter angka1 berupa 20 dan nilai angka2 berupa 10. Hasil yang dikembalikan dari server web service adalah angka 30.

Rectangular Selection Di NetBeans 7.1

Salah satu fitur baru yang menarik di editor NetBeans 7.1 adalah Rectangular Selection (shortcut CTRL+SHIFT+R).  Dengan fitur baru ini, programmer tidak lagi terikat untuk men-select kode program baris per baris.  Rectangular Selection sangat berguna untuk mengganti keyword yang berderet baris per baris tanpa mengganti keyword lain di setiap baris.   Sebagai contoh, terdapat deklarasi variabel seperti berikut ini:


private List<Kotak> lstOpen;
private List<Kotak> lstClose;
private Dunia dunia;
private Kotak curKotak;
private List<Kotak> lstHasil;

Lalu, programmer tiba-tiba memutuskan untuk mengganti keyword private pada seluruh baris di atas menjadi keyword public.

Ia dapat mulai dengan memilih keyword “private” yang ada dengan menggunakan Rectangular Selection tool seperti yang terlihat pada gambar berikut ini:

NetBeans 7.1 Rectangular Selection

NetBeans 7.1 Rectangular Selection

Kemudian, begitu mengetik “public” di keyword, seluruh kata “private” akan berubah menjadi “public“, seperti yang terlihat pada gambar berikut ini:

NetBeans 7.1 Rectangular Selection

NetBeans 7.1 Rectangular Selection

Membuat Album Foto Dengan PrimeFace Di NetBeans 7

PrimeFaces adalah salah satu framework ‘tampilan’ yang kompatibel dengan Java Server Faces 2.0.  Framework ini sudah di-bundle di NetBeans 7 sehingga pengguna NetBeans tidak perlu lagi men-download sendiri.  Artikel ini akan menunjukkan bagaimana memakai PrimeFaces di NetBeans 7.  Artikel ini hanya menunjukkan pemakaian komponen <galleria>.  Seluruh komponen yang disediakan oleh PrimeFaces dapat dilihat di show case yang berada di http://www.primefaces.org/showcase/ui

Langkah pertama yang dilakukan adalah membuat sebuah project baru di NetBeans 7, dengan memilih menu File, New Project.  Kemudian pilih Java Web, Web Application, seperti yang terlihat di gambar berikut:

Klik tombol Next, isi informasi project seperti Project Name dan Project Location.  Klik tombol Next lagi untuk membuka halaman Server and Settings.  Pada halaman ini, pilih Server yang akan dipakai.

Setelah itu, klik tombol Next, halaman Frameworks akan muncul.  Beri tanda centang pada JavaServer Faces.  Kemudian pada tab Components, pilih PrimeFaces 2.2.1 di Components Suite seperti yang terlihat pada gambar berikut:

Memilih PrimeFaces Pada Saat Membuat Project Web Baru
Setelah itu, klik tombol Finish.  Sebuah facelet dengan nama index.xhtml akan dibuat.  Kalau diperhatikan, facelet tersebut secara otomatis akan menyertakan namespace PrimeFaces, seperti yang terlihat di bagian berikut:

<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:p="http://primefaces.prime.com.tr/ui"
xmlns:h="http://java.sun.com/jsf/html">

Web site yang akan dibuat pada artikel ini tidak menyediakan fungsi upload, sehingga diasumsikan gambar sudah berada di lokasi yang ditentukan.  Sebagai informasi, folder yang dipakai adalah folder dengan nama gambar.  Buat sebuah folder baru di Web Pages dengan klik kanan dan memilih New, Other… Pada dialog yang muncul, pilih Other, Folder. Pada Folder Name, isi dengan nama gambar.  Masukkan beberapa file gambar pada folder ini dengan cara copy-paste.

Langkah berikutnya, buat sebuah Managed Bean dengan memilih menu File, New File.  Kemudian pilih JavaServer Faces pada bagian Categories, dan pilih JSF Managed Bean pada bagian File Types.  Klik tombol Next.  Isi Class Name dengan FileAlbum.  Pada combobox Scope, isi dengan session.  Kemudian klik tombol Finish.

Kemudian ganti kode program pada FileAlbum.java yang dihasilkan oleh NetBeans menjadi seperti berikut:

package co.id.snake.mbean;

import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.faces.application.Resource;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;

@ManagedBean
@SessionScoped
public class FileAlbum {

  private List<String> fileLocations;

  public FileAlbum() {
    fileLocations = new ArrayList<>();
    try {
      ServletContext sc = (ServletContext)FacesContext.getCurrentInstance().getExternalContext().getContext();
      Path dirGambar = Paths.get(sc.getRealPath("/gambar"));
      try (DirectoryStream<Path> dir = Files.newDirectoryStream(dirGambar)) {
        Iterator<Path> iter = dir.iterator();
        while (iter.hasNext()) {
          Path file = iter.next();
          fileLocations.add("/gambar/" + file.getFileName());
        }
      }
    } catch (IOException ex) {
      ex.printStackTrace();
    }
  }

  public List<String> getFileLocations() {
    return fileLocations;
  }
}

Kode program di atas memanfaatkan fitur baru di Java 7, sehingga hanya bisa dijalankan bila menggunakan JDK 7 ke atas.  Bila fitur baru belum dikenali oleh editor, klik kanan pada nama project, kemudian pilih Properties.  Pada bagian Source/Binary Format, pastikan JDK 7 sudah dipilih.

Setelah itu, lakukan modifikasi pada index.xhtml menjadi seperti berikut ini:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:p="http://primefaces.prime.com.tr/ui"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
   <title>Latihan PrimeFaces</title>
</h:head>
<h:body>
   <p:growl id="label" showDetail="true"/>
   <p:panel header="Album Foto">
     <p:galleria effect="slide" effectSpeed="1000">
       <ui:repeat value="#{fileAlbum.fileLocations}" var="fileLocation" >
         <p:graphicImage value="#{fileLocation}" />
       </ui:repeat>
     </p:galleria>
   </p:panel>
</h:body>
</html>

Tampilkan facelet tersebut di browser dengan memilih menu Run, Run File.  Berikut ini adalah contoh tampilan di browser:

Contoh Tampilan PrimeFaces

Video yang mempertunjukkan langkah demi langkah dari artikel ini dapat dilihat di http://www.screencast.com/t/C6KdmBmLCMn.

Konfigurasi J2ME Polish

Framework J2ME Polish menyertakan build.xml yang merupakan build file Apache Ant yang dipakai untuk men-compile dan menjalankan emulator.   Dengan demikian, pada dasarnya, J2ME Polish dapat dipakai pada IDE apa saja asalkan telah mendukung Apache Ant.  Salah satu pengecualian adalah pada IDE NetBeans karena IDE tersebut telah menggunakan Apache Ant untuk menjalankan tugas-tugas standar, sehingga programmer harus memakai file build-netbeans.xml yang akan meng-‘extends‘ task bawaan NetBeans (yang terletak di lokasi nbproject/build-impl.xml).  Bila hal ini menyebabkan perilaku NetBeans menjadi aneh, sebaiknya jangan menggunakan plugin J2ME Polish untuk NetBeans!  Sebaliknya, jalankan build.xml secara manual atau terpisah dari IDE tersebut.  Pada IDE Eclipse, seseorang dapat memilih menu Window, Show View, Others.., kemudian memilih Ant, Ant.  Pada window yang muncul, klik kanan bagian kosong dan pilih Add Buildfiles…, kemudian pilih build.xml bawaan J2ME Polish yang telah di-copy ke folder project sebelumnya.

Tanpa menggunakan plugin, project dapat dibuat seperti membuat project Java ME biasanya.  Bedanya, file build.xml dan resources yang diperlukan harus di-copy secara manual ke folder project yang telah dibuat.  Setelah itu, buka file build.xml dan lakukan perubahan pada file tersebut.

Target <target name=”j2mepolish”> adalah bagian yang paling sering harus diubah.  Pada target ini dapat ditemukan tag <j2mepolish> yang di dalamnya terdapat sejumlah tag lagi, seperti <info>, <deviceRequirements>, <build>, dan <emulator>.

Tag <info> berisi informasi mengenai MIDlet, yang dapat diubah sesuai kebutuhan, misalnya:

<info
  name="Latihan MIDlet"
  version="1.0.0"
  description="Latihan pertama saya"
  vendorName="SolidSnake"
  infoUrl="https://thesolidsnake.wordpress.com"
  jarName="latihan.jar"
  jarUrl="${polish.jarName}"
  copyright="Copyright 2011 SolidSnake."
/>

Informasi yang ada di tag <info> nantinya akan mempengaruhi isi file JAD yang dihasilkan.  Sebagai catatan, file JAD adalah file teks yang berisi informasi mengenai aplikasi, yang akan di-download oleh pengguna sebelum men-download file JAR.

Tag <deviceRequirements> merupakan salah satu kelebihan memakai J2ME Polish!!  Dengan adanya tag ini, kita dapat menentukan target perangkat mobile dari aplikasi.  J2ME Polish memiliki sejumlah besar daftar perangkat yang tersimpan di file vendors.xml, devices.xml, dan capabilities.xml.  Ketiga file ini telah terdapat dalam file enough-j2mepolish-build.jar.  Untuk melihat ketiga file ini, buka file enough-j2mepolish-build.jar dengan program yang dapat membaca arsip zip.  Bila daftar yang ada dinilai masih kurang, seseorang dapat menambahkan perangkat baru di file custom-devices.xml.

Di dalam tag <deviceRequirements>, terdapat satu atau lebih tag <requirement>yang menjadi persyaratan bagi perangkat yang dapat menjalankan aplikasi ini.  Cara yang paling gampang adalah menyamakan Identifier dari perangkat, seperti yang terlihat di:

<deviceRequirements>
  <requirement name="Identifier" value="Generic/AnyMidp1Phone" />
</deviceRequirements>

Jika ingin platform yang lebih spesifik, nilai value pada Identifier dapat diganti menjadi seperti “Nokia/Series40E3”, “Sony-Ericsson/JavaPlatform7”, dan sebagainya.  Nilai ini harus sesuai dengan yang ada di vendors.xml dan devices.xml.

Lalu apa yang membuat <deviceRequirements> berguna?  Tag ini memiliki atribut if dan unless, sehingga seseorang bisa mengatur deviceRequirement apa saja yang aktif berdasarkan property Ant.  Misalnya, jika terdapat konfigurasi seperti:

<deviceRequirements if="untukNokiaS40Saja">
  <requirement name="Identifier" value="Nokia/Series40E3" />
</deviceRequirements>
<deviceRequirements if="untukSEJP7Saja">
  <requirement name="Identifier" value="Sony-Ericsson/JavaPlatform7" />
</deviceRequirements>

maka jika <property name=”untukNokiaS40″ value=”true” /> dipanggil sebelumnya, maka hanya deviceRequirements tersebut saja yang aktif.  Dengan demikian, seseorang bisa membuat target seperti “jalankanNokia“, “jalankanSonyEricson“, dan sebagainya, sehingga proses pengembangan aplikasi yang sama untuk banyak vendor berbeda menjadi mudah.

Tag <build> akan men-compile dan membuat file JAR dari kode program.  Tag ini memiliki sejumlah elemen seperti <midlet>, <variables>, <resources>, <obfuscator>, dan lainnya.  Yang harus diubah adalah tag <midlet> dimana programmer harus menentukan class MIDlet dan nama MIDlet.  Satu hal yang berguna dan tidak ditemui pada IDE standar adalah tag <midlet> juga mendukung atribut if.  Ini berarti seseorang dapat menentukan MIDlet apa saja yang akan menjadi bagian dari JAR berdasarkan kondisi tertentu!  Sementara pada IDE seperti NetBeans dan Eclipse, seluruh MIDlet dalam proyek yang sama akan di-bundle menjadi satu kesatuan, tanpa pengkondisian tertentu.

Terakhir, untuk menjalankan emulator, tambahkan tag <emulator>.  Tag ini sangat sederhana, hanya terdiri dari atribut seperti wait, securityDomain, enableProfiler, enableMemoryMonitor, dan sebagainya.  Perlu diingat bahwa programmer TIDAK menentukan secara manual emulator apa yang akan dijalankan.  J2ME Polish secara otomatis menentukan emulator yang akan dijalankan berdasarkan pengaturan di deviceRequirements.  Pada banyak kasus, J2ME Polish akan menjalankan MicroEmulator yang sudah ter-install bersama dengannya.  MicroEmulator adalah emulator JME yang berjalan pada Java Standard Edition.

Bila tidak ingin memakai MicroEmulator, melainkan emulator bawaan Java ME Platform SDK, gunakan Identifier seperti Generic/AnyMidp1Phone pada deviceRequirements.  Perlu diingat bahwa Java ME Platform SDK mungkin akan menolak menjalankan JAR yang telah mengandung file-file class J2ME Polish karena memiliki ukuran yang besar, di atas 1 MB.  Untuk mengatasi permasalahan ini, masuk ke direktori instalasi Java ME Platform SDK 3.0, kemudian buka direktori runtimes, lalu cldc-hi-javafx, dan kemudian buka direktori bin.  Edit file jwc_properties.ini yang terdapat pada direktori tersebut dengan notepad atau editor lainnya.  Gunakan fitur search untuk mencari tulisan system.jam_space, kemudian ganti nilai 1000000 menjadi nilai yang lebih besar.

Setelah itu, tutup device-manager.exe melalui icon di taskbar ataupun melaui task manager.  Jalankan kembali target Ant j2mepolish, dan kini emulator Java ME Platform SDK akan menampilkan MIDlet dengan lancar.  Tapi satu hal yang perlu diingat adalah pada kenyataannya, sama seperti emulator yang sebelumnya menolak, perangkat mobile lama mungkin juga tidak mendukung file JAR yang besar.

Memakai J2ME Polish Di Dalam NetBeans

J2ME?  Sebuah nama yang masih mewakili generasi lama, karena Sun (kini dibeli Oracle) sudah lama mengganti nama Java 2 Micro Edition (J2ME)  menjadi Java Micro Edition (JME).  Dari sisi teknologi sendiri, kini sudah ada Java FX yang semakin didukung.  Lalu kenapa masih memakai J2ME Polish?

J2ME Polish adalah sebuah framework tambahan dari Enough Software dan bersifat open-source.  J2ME Polish terdiri atas beberapa komponen, seperti:

  • Lush,  untuk perancangan user interface.
  • Janus, untuk transcoding aplikasi Java Micro Edition ke BlackBerry atau Android.
  • Touch, untuk mempermudah pemograman networking.
  • Trunk, untuk menyederhanakan proses menyimpan dan membaca data.
  • Marjory, merupakan kumpulan database yang berisi informasi perangkat mobile, yang dihimpun bersama oleh komunitas.

Pada konotasi secara umum dan juga pada artikel ini, J2ME Polish sering dirujuk dengan komponen Lush-nya, sehingga asumsi-nya J2ME Polish adalah framework berbasis GUI.

Jika memang demikian, apa kelebihan framework user interface di J2ME Polish?  Pada beberapa framework lain, seperti Kuix (Kalmeo User Interface eXtensions), tampilan user interface digantikan sepenuhnya dengan menggunakan XML.  J2ME Polish mengambil pendekatan yang berbeda, dimana J2ME Polish tetap menggunakan class-class LCDUI seperti class Form dan turunan Item (TextField, StringItem, dsb).  Hal ini berarti untuk beralih dari proyek yang sudah ada ke J2ME Polish, programmer tidak perlu mengubah kode program yang sudah ada.  J2ME Polish tentu saja juga menyediakan class-class tambahan, seperti TabbedForm, TreeItem, dan sebagainya.  Setiap komponen tersebut dapat di-customize dengan membuat sebuah file teks yang menggunakan syntax CSS.

Kelemahan J2ME Polish, sama seperti framework lainnya yang bukan merupakan bagian dari standar Java, adalah ukuran JAR yang meningkat beberapa kilobyte.  Ini karena JAR harus menyertakan kode program J2ME Polish.

File JAR J2ME Polish dapat di-download di http://www.enough.de/products/j2me-polish/download.  File berukuran sekitar 52 MB tersebut merupakan sebuah aplikas Java Standard Edition yang berfungsi sebagai installer.  Ketik perintah berikut di command prompt untuk memulai proses instalasi:

java - jar j2mepolish-2.2.1.jar

Installer akan meminta beberapa informasi lokasi direktori, seperti lokasi instalasi NetBeans dan Java ME Platforms SDK.  Installer juga menawarkan untuk menyiapkan sebuah plugin bagi NetBeans sehingga NetBeans dapat langsung menjalankan MIDlet yang memakai framework J2ME Polish.

Salah satu hal yang perlu diperhatikan bila melakukan instalasi plugin J2ME Polish untuk  NetBeans 7  di Windows 7 adalah  jangan lupa menjalankan NetBeans 7 dengan hak akses administrator.  Bila pada saat melakukan update plugin, NetBeans 7 tidak memiliki hak akses administrator, ia akan terus me-restart dirinya sendiri walaupun aplikasinya sudah ditutup.   Solusinya, tutup NetBeans 7 melalui Task Manager, kemudian jalankan kembali NetBeans 7 dengan men-klik kanan icon-nya lalu memilih Run as administrator.

Bila plugin telah ter-install dengan benar, pengguna dapat segera membuat proyek baru dengan memilih menu File, New Project, Java ME, dan men-klik pada J2ME Polish Project.  Kotak dialog New Project yang muncul terlihat sedikit berbeda dari biasanya.  Misalnya, sekarang pengguna dapat menentukan lokasi ia men-install J2ME Polish.  Akan tetapi, halaman yang paling berubah dari biasanya adalah halaman Select Target Devices.  Pilihan device terlihat semakin banyak berkat komponen Marjory dari J2ME Polish.  Coba mulai dengan memilih Configuration “CLDC/1.1“, profiles “MIDP/2.1“, dan salah satu device Nokia seperti “Nokia E66″.

Halaman "Select Device Type"

Di NetBeans, J2ME Polish membuat turunan dari build-impl.xml milik NetBeans sehingga pada saat tombol “Run” ditekan, yang akan dikerjakan adalah Ant’s Task milik proyek J2ME Polish.  Untuk melihat Ant’s Task yang telah dimodifikasi tersebut, buka proyek melalui window Files, kemudian double-click pada build.xml.

Saya menemukan masalah pada saat akan menjalankan proyek, dimana window Output memunculkan kesalahan:

java.io.IOException: Cannot run program "jvisualvm": CreateProcess error=2, The system cannot find the file specified

Kesalahan ini terjadi karena pada saat menjalankan emulator, J2ME Polish juga menjalankan profiler, dalam hal ini adalah JVisualVM.  Akan tetapi cara pemanggilan JVisualVM tersebut tidak diikuti dengan lokasi path yang lengkap!  Hal ini menyebabkan ProcessBuilder tidak menemukan file yang akan dijalankan.

Solusi yang paling mudah adalah dengan meng-edit file build.xml untuk mematikan profiler.  Lagipula, bagi sebagian orang, menjalankan JVisualVM setiap kali program di-run adalah hal yang menganggu.  Pada bagian <target name=”j2mepolish”>, cari bagian yang bertanggung jawab untuk memanggil emulator, yang isinya seperti berikut ini:

<emulator wait="true" trace="class" securityDomain="trusted" enableProfiler="true" enableMemoryMonitor="false" enableNetworkMonitor="false" if="test and not debug" ></emulator>

Ganti nilai “true” pada atribut enableProfiler, enableMemoryMonitor, dan enableNetworkMonitor menjadi “false“.  Setelah itu, emulator J2ME Polish harusnya dapat berjalan dengan lancar, seperti pada tampilan berikut ini:

Tampilan J2ME Polish

Tampilan J2ME Polish

Game API di Java Micro Edition

Sebentar lagi masa kuliah semester genap akan berakhir, saatnya untuk liburan panjang… Aku akui liburan panjang hingga bulan September mendatang menyebabkan hampir gaji tiga bulan menjadi ‘kosong’..  Tapi dari sisi lain, liburan ini berarti aku bisa berpesta ria dengan aneka kode program tanpa diganggu sedikit pun.  Bayangkan, waktu kerja kantoran dulu, jatah cuti hanya 12 hari selama setahun.. Dan sekarang, sebagai dosen, aku bisa cuti selama dua bulan!!!

Selama mengajar dua semester ini, aku lebih banyak menghabiskan waktu menulis materi di modul kuliah ketimbang menulis di blog.  Maklum, itu merupakan salah satu tugas seorang dosen..  Salah satu mata kuliah menarik yang harus aku ajarkan adalah pemograman mobile dengan Java Micro Edition..  Aku sudah sering bermain-main dengan Java Enterprise Edition & Java Standard Edition, tapi baru kali ini menyentuh JME..  Sebagai informasi, aplikasi Android juga diprogram dengan Java, tetapi bukan versi JME..  Aplikasi BlackBerry sendiri mendukung JME, tetapi juga punya pengembangan aplikasi berbasis Java-nya sendiri yang khas untuk BlackBerry.

Salah satu hal menarik yang dari JME adalah dukungan Game API bawaan.  Hal ini karena JME banyak dipakai untuk membuat aplikasi game, istilah gaulnya: “game java” sehingga ia disertai dengan peralatan yang sangat membantu dalam pembuatan game. Inti dari Game API di JME adalah class GameCanvas yang merupakan turunan dari class Canvas.

Class GameCanvas menyediakan method getGraphics() dan flushGraphics() untuk mendukung double buffering.  Programmer bisa mendapatkan sebuah Graphics dengan memanggil getGraphics(), kemudian menggambar dengan menggunakan context tersebut, baru setelah selesai menggambar dan ingin menampilkan ke layar, ia tinggal memanggil flushGraphics().

Class lain dalam Game API adalah class TiledLayer dan class Sprite.  Kedua class tersebut mewakili objek dalam game yang dapat digambar secara otomatis oleh class LayerManager.

Salah satu cara untuk memahami konsep Layer di Game API adalah dengan memanfaatkan Game Builder dari NetBeans IDE.  Game Builder bukanlah bagian dari spesifikasi JME, melainkan alat bantu yang ditawarkan oleh NetBeans IDE.  Versi terbaru dari NetBeans IDE, yaitu versi 7.0, dapat didownload di http://netbeans.org/community/releases/70/ .

Untuk membuat sebuah Game Builder baru, klik kanan pada nama package, kemudian pilih New, Game Builder…  Berikut ini adalah contoh tampilan sample Game Builder dari NetBeans:

Tampilan Game Builder

Tampilan Game Builder

Scenes mewakili apa yang akan ditampilkan di layar nantinya, terdiri atas satu atau lebih TiledLayer dan Sprite.

TiledLayer adalah sebuah layer yang terdiri atas kotak-kotak dimana setiap ‘kotak’ ini diisi dengan gambar tertentu.  Perancang game harus membuat sebuah file gambar yang merupakan gabungan dari seluruh elemen yang dapat di-isi-kan ke dalam TiledLayer tersebut.  Contoh file gambarnya seperti:

Contoh Gambar Untuk Game API

Contoh Gambar Untuk Game API

Game Builder menawarkan kemudahan untuk mengisi setiap kotak atau ’tile’ yang ada di gambar secara visual, seperti yang terlihat di gambar berikut:

Tiled Layer Editor

Tiled Layer Editor

Pembuat game dapat memisahkan setiap elemen interaksi yang berbeda ke dalam TiledLayer yang berbeda.  Misalnya sebuah TiledLayer untuk background game, dan sebuah TiledLayer lagi untuk mewakili bebatuan atau penghalang.  Dengan demikian, pada saat karakter utama bergerak, programmer dapat memanggil method collidesWith() untuk memeriksa apakah karakter bersinggungan dengan TiledLayer tertentu.

Karakter yang ada di game diwakili oleh class Sprite.  Game Builder menyediakan editor visual untuk merancang dan memutar animasi sebuah Sprite seperti pada contoh tampilan berikut ini:

Sprite Editor

Sprite Editor

Setelah selesai merancang TiledLayer dan Sprite, yang harus dilakukan berikutnya adalah menggambar mereka di layar dengan menggunakan method paint() dari LayerManager.  Jangan khawatir soal pergeseran layar karena programmer dapat memanggil method setViewWindow() milik LayerManager untuk mengkliping layar.

Berikut ini adalah contoh tampilan hasil game yang dibuat dengan Game Builder bila dijalankan menggunakan emulator bawaan JME:

Contoh Tampilan

Contoh Tampilan