Tuesday, December 21, 2004

Java Date().getTime() dan TO_DATE Oracle

Di Java kita biasa menggunakan getTime() dari class java.util.Date untuk mendapatkan nilai long dari waktu saat ini. Method getTime() akan menghasilkan nilai (number) milidetik yang merupakan selisih dari tanggal saat ini dengan tanggal 1 Januari1970, 00:00:00 GMT. Hal yang sama juga kita dapatkan dengan memanggil System.currentTimeMillis().

Jika kita menggunakan nilai tersebut untuk menyipan informasi tanggal pada database oracle, bagaimana kita mendapatkan tanggal dari nilai tersebut?

Misalkan kita punya tabel DATETABLE dan memiliki kolom DATEMILLIS yang berisi nilai long dari getTime(), maka kita bisa mendapatkan tanggal dengan cara :

SELECT TO_DATE('01011970 00:00:00','DDMMYYYY HH24:MI:SS') + DATEMILLIS/86400000 FROM DATETABLE

Sunday, December 05, 2004

Saat capek & sedikit waktu

Saat capek dan cuma ada sedikit waktu untuk menyelesaikan coding, beberapa programmer lebih memilih tidur. Kenapa? karena kondisi lelah hanya akan menghasilkan bug baru. Solusi untuk tidak melanjutkan coding berarti dengan konsekuensi program tidak kelar, alias harus cari alasan untuk bisa diberi tambahan waktu atau deadline yang mundur.

Beberapa programmer pada waktu lelah menjadi tergesa-gesa, berfikir lebih cepat, bekerja lebih cepat tapi mejadi lebih banyak trial and error.

Wednesday, November 24, 2004

Random number

http://random.mat.sbg.ac.at/
http://www.gnu.org/software/gsl/manual/gsl-ref_17.html
http://cgm.cs.mcgill.ca/~luc/rng.html

Thursday, November 11, 2004

Jangan percaya cost dari oracle optimizer?

Consider Cost or Time - trying to compare the COST of two queries. Diskusi dari website asktom ini cukup menarik, karena kita biasanya Oracle DBA menggunakan cost untuk menentukan query mana yang performancenya bagus (bisanya berarti query yang eksekusinya cepat).

Diskusinya sangat panjang, sudah ada sejak tahun 2000 tapi sedikit potongan komentar tom ini mungkin bisa jadi acuan :
You cannot compare costs across queries, even if the queries are "identical".


You cannot make any judgments about the relative performance of a query based on
the cost (queries with tiny costs may take days to run, queries with huge costs
could run in milliseconds).

Thursday, November 04, 2004

WAS craches

Websphere application server saya, beberapa waktu lalu crash dan menghasilkan sebuah file heap dump yang besar (800MB). Waktu itu sempat membuat panik karena terjadi berulang-ulang di mesin production, setelah itu masalah lain muncul: WAS crashes dan mengasilkan file javacore.

Untuk mengalisis penyebab WAS crashes link penting sebagai sumber bacaan adalah:
Setelah itu mulailah download tools untuk men-debug memory leak misalnya Heaproots atau HeapWizard dan untuk memulainya coba baca tulisan ini: (Near?) zero overhead debugging with the IBM JVM.

Sunday, October 31, 2004

Result Set dari Oracle function/procedure

Oracle procedure ataupun function dapat mengebalikan nilai dengan tipe cursor, tipe data cusrsor mirip dengan ResultSet di Java, jadi kita bisa menggunakan nilai balikan function/procedure cursor menjadi ResultSet pada program Java.

Dibawah ini contoh Oracle function dan procedure yang menghasilkan curson

create or replace package types as
type cursorType is ref cursor;
end;
/

create or replace function sp_ListEmp return types.cursortype as
l_cursor types.cursorType;
begin
open l_cursor for select ename, empno from emp order by ename;
return l_cursor;
end;
/

create or replace procedure getemps( p_cursor in out types.cursorType ) as
begin
open p_cursor for select ename, empno from emp order by ename;
end;
/


Penggunaan pada program Java-nya seperti ini:

java.sql.Connection conn = null;
...
String query = "begin :1 := sp_listEmp; end;";
CallableStatement cstmt = conn.prepareCall(query);
cstmt.registerOutParameter(1,OracleTypes.CURSOR);
cstmt.execute();
ResultSet rset = (ResultSet)cstmt.getObject(1);

Referensi: http://asktom.oracle.com/~tkyte/ResultSets/



Oracle: Function Based Indexes bisa mempercepat eksekusi function

Beberapa waktu yang lalu proyek saya mempunyai masalah pada performance database. Ini pertama kalinya saya berhadapan dengan masalah performance yang cukup besar. Masalah adalah pada proses batch, proses untuk mengambil data dari file-file teks, parsing, validasi, dan memasukannya ke database Oracle dalam jumlah yang sangat besar.

Proyek selesai, masalah performansi dapat diatasi dengan tuning pada parameter database dan sedikit pada query. Tapi setelah beberapa waktu, database production mengalami masalah yang sama, data semakin besar dan tim mulai melakukan perombakan-perombakan besar pada query.

Database specialist mulai melihat procedure/function yang ada di Oracle database. Salah satu komentarnya ketika melihat banyakannya function TRUNC() digunakan adalah hal itu bisa dipercepat dengan membuat indeks pada fungsi. Aneh kedengarannya, fungsi bisa di-indeks? Tapi memang benar, fungsi pada suatu kolom pada tabel tertentu bisa di-indeks. Jadi intinya, kita membuat indeks untuk suatu kolom dengan menggunakan function pada nilai-nilai kolom tersebut. Dengan demikian, execution plan pada query dengan menggunakan function yang tadinya "TABLE ACCESS (FULL)" akan menjadi "INDEX (RANGE SCAN)" yang berarti akan lebih cepat.

Contoh dibawah ini adalah cara untuk membuat function based indexes pada kolom FIRST_NAME di tabel EMPLOYEE dengan function upper(FIRST_NAME) :

create index EMP_UPPER_INDEX on EMPLOYEE(upper(FIRST_NAME));


Tapi untuk menggunakan Function Based Indexes, kita perlu hati-hati karena ada kelemahannya juga yaitu proses insert dan update akan menjadi lebih lambat kira-kira 5 kali. Untuk proses insert yang banyak dalam satu waktu seperti pada proses batch, akan menjadi delay yang sangat signifikan. Jadi perlu pertimbangan yang detail untuk menerapkan stategi baru, karena biasanya tidak terlepas dengan pertimbangan keuntungan dan kerugiannya. Artikel referensi ini harus dibaca untuk pengertian yang lebih baik tentang function based indexes :




PL/SQL coding standard

Minggu ini adalah minggu pertama kali saya benar-benar harus coding dengan PL/SQL. Membaca code orang memang cukup melelahkan apalagi dengan gaya yang sedikit acak-acakan, identasi tiap line yang kurang bagus, penamaan variabel yang tidak mudah dimengerti (hati-hati memberi nama varibel di PL/SQL jangan sampai sama dengan nama kolom dalam query select yang ada di procedure/function yang dibuat), dan cara-cara yang tidak efektif.

Memang tidak mudah untuk membuat program pertama kali langsung bagus, maka dari itu kita perlu belajar dulu bagaimana membuat program yang baik bukan sekedar membuat program yang berjalan dengan benar (hasil outputnya benar). Ciri utama program yang baik adalah selalu memperhatikan berbagai aspek. Dari sisi bisnis program itu haruslah benar, dan ini hanya terjadi jika program kita telah ditest. Program yang benar belum bisa dikatakan benar walaupun kelihatannya begitu. Dari sisi sistem, program yang baik haruslah memperhatikan aspek-aspek seperti performance, security, maintainability dan lain-lain.

Itulah sebabnya diawal pekerjaan kita, kita perlu membuat coding style standard atau mengikuti standar yang sudah dibuat orang. Kita juga perlu mencari tips/tricks bagaimana menulis program yang baik.

Tidak mudah untuk menemukan PL/SQL coding standard. Masih lebih mudah untuk mencari tips/tricks untuk coding yang baik, yang meperhatikan performance (kecepatan mempereroleh/memanipulasi data) pada database, karena performance untuk data yang besar pada database selalu jadi masalah. Website dibawah ini adalah salah satu dokumen PL/SQL coding standard yang bisa jadi referensi untuk membuat program dengan PL/SQL di Oracle :



Thursday, October 28, 2004

Create java executable file in Windows

To create executable file for java application inWindows, so you just do one click to launch:

1. create a bat file with the following line

START java -jar JARFILE

or

javaw -jar JARFILE

START or javaw command makes java application run without command prompt showing to your screen

4. Using Nullsoft (NSIS) script or JELUDE

4. Free tools, see related links in Jelude page

Tuesday, October 19, 2004

Windows script untuk mengubah ip address

Sering kali kita perlu mengubah-ubah setting ip address komputer Windows dan yang kita lakukan adalah membuka window connection properties dan megubah ip address secara manual. Jika perubahan sering maka mengubah dengan cara seperti itu akan jadi pekerjaan yang menyebalkan.

Supaya pekerjaan tersebut menjadi mudah kita bisa menggunakan perintah netsh dari command prompt. Dibawah ini contoh penggunaan perintah netsh:
 netsh int ip set address "LAN" source=dhcp

Perintah diatas akan mengeset connection dengan nama "LAN" untuk obtain IP address automaticaly alias menggunakan DHCP. Jika tidak ada conncetion dengan nama "LAN" maka perintah tersebut akan menghasilkan error Invalid interface LAN specified.. Untuk merubah nama connection, klik Start > Setting > Network and Dial-up Connection, lalu pilih (klik) connection yang akan di-rename, klik-kanan > rename.
Dibawah ini contoh mengubah connection ke static IP 3.241.30.114 dengan netmask 255.255.0.0:

netsh int ip set address "LAN" static 3.241.30.114 255.255.0.0

Untuk mempermudah gonta-ganti IP, maka buat saja BAT file dari perintah diatas. Jadi kalo mau ngubah IP tinggal klik aja.

Monday, October 18, 2004

WSAD trik: mengubah alamat CVS server

Kalau kita pake WSAD (IBM Websphere Application Developer) trus kita ubah alamat sever CVS yang kita gunakan, maka kita akan kesulitan melakukan setting perubahan tersebut tanpa kehilangan informasi sikronisasi (CVS meta information) terakhir dengan server CVS.

Kita dapat dengan mudah membuat "repository location" baru dan menghapus "repository location" yang lama pada CVS perspective. Kemudian men-disconnect tiap folder dengan cara folder pada package explorer, kemudian pilih "Team" > "Disconect". Setelah itu akan ada window konfirmasi yang menyuruh kita menghapus meta information atau tidak. Jika kita pilih tidak, maka saat kita akan mengeset folder/project tersebut agar terkoneksi dengan CVS dengan cara klik kanan folder, pilih "Team" > "Share Project" makaserver CVS tidak akan berubah dari sebelumnya.

Jika kita pilih menghapus meta information CVS, maka setelah terkoneksi dengan server CVS yang baru kode kita akan terlihat konflik semua dengan kode yang ada di CVS. Tentu saja ini sangat menjengkelkan jika kita telah ...

..bersambung

Friday, October 15, 2004

WAS fixpack

My current WAS version is 5.1.0.3 and try to applying WebSphere Application Server 5.1.0 Cumulative Fix 5 (5.1.0.5). First, I get the fixpack from :

http://www-1.ibm.com/support/docview.wss?rs=180&context=SSEQTP&uid=swg24007453&loc=en_US&cs=utf-8〈=en

It's a quite simple but li'll bit scary coz this my first time and the WAS is on production system.
I don't know where to start. So I start to reading README file from the link above, then I know what should I do.

If you find the subject of "Finding the readme_updateinstaller.txt, readme_updateinstaller.html and readme_updateinstaller.pdf files", and don't know where the file is, just follow the link bellow:

http://publib.boulder.ibm.com/infocenter/ws51help/index.jsp?tab=search&searchWord=+readme_updateinstaller+5.1.0.5&maxHits=50

here is the step to applying the fixpack...

1. Download the fixpack.
2. Unpack the zip file in C:\Websphere\update (FYI, my WAS installed in C:\Websphere)
3. Stop the WAS using stopServer command
4. Run C:\WebSphere\AppServer\bin\SetupCmdLine.bat to set JAVA_HOME path
5. Then run C:\Websphere\update\updateWizard.bat and follow the wizard, just click next and next ... until finish



Tuesday, October 12, 2004

Joke: IT resource management

Teman saya baru aja keluar dari perusahaan, dia meninggalkan setumpuk code pada satu proyek. Saya masuk dalam proyek yang ditinggalkannya hanya dengan hand-over yang cuma dilakukan beberapa jam dengan cara diskusi apa yang masih perlu dilakukan dan isu-isu yang ada. Beberapa bug tertinggal dalam proyek tersebut dan tentu saja seperti biasanya minim dokumentasi.

Kejadian seperti itu bukan cuma sekali. Di bidang IT di Indonesia hal itu banyak terjadi. Saya gak ngerti bagaimana perusahan2 itu melakukan resource management.

Kalo kita runut lagi kebelakang, sebelum proyek dimulai, memang banyak kesalahan-kesalahan yang sering terjadi di proyek IT pada saat awal proses. Penyebab pertama dan yang utama biasanya adalah uang atau keuntungan. Seperti terjadi di semua perusahaan, di perusahaan IT pun profit pasti jadi tujuan utama. Tapi bagaimana bisa dengan harga perorang USD 200 sampai 350 perjam, project masih 'gagal' hanya karena minimalisasi resource demi minimalisasi cost project.

Yang terjadi di proyek IT yang riil kadang lebih parah. Misalnya, saat rencana tertulis 10 orang, sedangkan kenyataannya saat proyek berjalan, resource lebih kecil dari itu. Kalo kata teman saya, seirng ada 'developer bayangan' pada saat planning. Developer tersebut kenyataannya tidak pernah ada, dan pekerjaan developer bayangan itu kanyatannya menjadi pekerjaan developer riil. Hal tesebut bukanlah suatu mark-up yaitu untuk mendapatkan keuntungan yang lebih besar kemudian manajemen mencoba me-markup resource sehingga nilai proyek jadi lebih besar. Yang terjadi biasanya adalah mark-down yaitu mengurangi resource agar biaya produksi bisa ditekan sekecil mungkin. Kondisi seperti itu fatal karena proyek jelas sekali akan beresiko gagal. Resiko gagal ada karena developer kelebihan kerjaan sehingga pekerjaan bisa jadi tidak selesai tepat waktunya atau bagaian-bagain penting dalam proyek yang tidak utama tapi sebenernya penting seperti dokumentasi (sampai ke level source code) tidak dilakukan. Ada juga kemungkinan developer yang mengerjakan proyek sakit, stres, resign, atau bahkan mati :) gara-gara keseringan begadang, banyak minum kopi dan merokok sehingga resource berkurang.

Kejadian-kejadian seperti ini biasanya baru disadari setelah proyek mendekati terlihat kritis: perkerjaan masih banyak, waktu tinggal sedikit. Proyek semakin parah dengan menghilangnya beberapa developer karena developer kurang tangguh atau tidak cukup iman untuk berbakti kepada perusahaan. Apa yang dilakukan manajemen pada saat seperti itu? Ambil resource lain dari proyek yang tidak kritis, atau cari resource baru, atau meeting, meeting dan meeting.

Akhirnya UAT datang juga. Proyek selesai, tapi bug dimana-mana. Berutunglah kalau client tidak cukup pintar untuk menemukan bug dengan cepat. Dengan trik-trik khusus, client akan senang dengan hasil proyek. Tapi cepat atau lambat bug ditemukan juga, masalah-masalah lain ditemukan seperti berkurangnya performance sistem, sulitnya maintenance process dan lain-lain.

Demi memuaskan client (kalau manajemen tidak putusa asa) akhirnya untuk menyelesaikan masalah-masalah yang ada, ditambahlah beberapa orang developer untuk bug fixing atau penambahan-penambahan kecil permintaan client atau manajemen memutuskan membeli software lain untuk optimasi. Jadi akhirnya terjadi cost tambahan dibelakang, proyek sudah terlanjur 'gagal' dan cost pun tidak jadi terminimalisasi.

Parahnya, kondisi seperti itu biasanya terjadi lagi di proyek berikutnya.

Monday, October 11, 2004

Cara copy file lewat windows sharing

Kalo kamu butuh library untuk koneksi dengan SMB/CIFS seperti untuk maping windows network drive atau untuk copy file antar mesin Windows lewat folder sharing dan lain-lain, gunakanlah jCIFS. jCIFS dapat diperoleh dengan gratis di http://jcifs.samba.org

Dibawah ini contoh code untuk meng-copy file ejlp12.txt lewat folder sharing windows dari komputer 3.110.110.57 ke direktori lokal C:
import java.io.File;

import java.io.FileOutputStream;
import jcifs.smb.SmbFileInputStream;

/**
* Copy file from remote host to local disk
*/
public class CopyFile {
public static void main(String[] argx) throws Exception {
// Set IP lokal, nama file dan tempat dimana file hasil copy disimpan
String localIP = "3.110.110.12";
String localFile = "C:\\ejlp12.txt";

// Set IP remote, user, password, nama file dan tempat file yang akan di-copy
String sambaUser = "Administrator";
String sambaPassword = "master";
String remoteComputer = "3.110.110.57";
String sharedDirectory = "/D$/";
String remoteFile = "ejlp12.txt";

jcifs.Config.setProperty( "wins", localIP );
SmbFileInputStream in = new SmbFileInputStream(
new StringBuffer("smb://").append(sambaUser).append(":")
.append(sambaPassword).append("@").append(remoteComputer)
.append(sharedDirectory).append(remoteFile).toString());
FileOutputStream out = new FileOutputStream(new File(localFile));
byte[] b = new byte[8192];
int n;
while(( n = in.read( b )) > 0 ) {
out.write(b,0,n);
}
out.flush();
out.close();
}
}


Sederhana dan gampang kan?

Sunday, October 10, 2004

UI bad practice: fake component

Kadang-kadang kita ingin mempercantik web interface, mempermudah interaksi antara user dan sistem dengan menambahkan beberapa komponen html atau komponen form html dan menambahakan script untuk otomasi interaksi atau untuk membuatnya telihat lebih indah/keren. Tapi sayangnya banyak designer UI malah membuatnya semakin rumit, sulit didebug, dan justru malah mempersulit user karena user perlu waktu untuk mempelajari komponen yang diotomasi tersebut.

Penambahan komponen-komponen form-html untuk otomasi juga membuat halaman html menjadi 'kotor'. Komponen-komponen form tersebut menjadi fake component yang membuat data yang dikirim ke server (POST/GET) menjadi panjang. Membuat parameter-parameter baru yang sebenarnya tidak pernah dibutuhkan/diproses oleh server. Sebagai contoh, misalnya untuk suatu komponen input yang bernama "currencyId", seorang designer UI yang buruk bisa jadi membuat fake component seperti "currencyCode", "currencyDescription". Kita bisa tebak apa yang dia inginkan dari nama komponent-komponent fake tersebut. Dari fake components tersebut maka data pada request POST atau URL pada request GET akan menjadi seperti ini:

...¤cyId=12&currencyCode=¤cyDesciption=&...

Dari contoh diatas kita lihat ada fake parameters yang mungkin tidak pernah ada nilainya (value). Anda mungkin berfikir tidak ada yang salah dengan hal itu karena parameter-parameter tersebut tidak memberikan kontribusi terlalu signifikan dalam performance. Memang, dengan sedikit fake component pengaruhnya tidak signifikan tapi saya tidak berbicara tentang performance disini.

Yang menjadi concern utama saya disini adalah bagaimana kita harus mendesain UI sehingga memudahkan user dan meminimalisasi fake component. Penambahan otomasi user seharusnya mengurangi jumlah iteraksi antara user dan sistem. Jika otomasi atau apapun jenis enhancement pada UI kita membuat jumlah interaksi semakin lebih banyak maka lebih baik jangan lakukan enhancement tersebut. Untuk menghitung jumlah iteraksi sangan mudah, yaitu hitung saja jumlah aksi user terkecil seperti klik, mengerakkan kursor/mouse, menekan tombol keyboard, perpindahan tangan dari mouse ke keyboard dan lain-lain.

Oh ya, jangan lupa dengan adanya fake component dan javascript untuk mengotomatisasinya maka akan sulit juga buat kita untuk menggunakan validator framework yang umum. Bisa jadi akan menambahkan fake variabels di kode sisi server kita sebagai solusi (bad practice) agar kita tidak perlu mengubah kode validator framework yang digunakan.


Friday, October 08, 2004

Hirarki Apache

ASF punya banyak software/alikasi/program/library yang open source, cukup banyak dan populer. Tapi kalau kita ke website Apache.org kadang bingung mencari project yang kita cari apalagi kalau itu project yang masih baru belum rilis atau masih dalam incubator project.

Halaman "Hierarchy of The Apache Software Foundation" memberikan list yang cukup lengkap dari projects yang ada di ASF sehingga memudahkan kita untuk menemukannya.


Keep clean after you intrude on ...

Remainder list untuk Windows intruder :
  • Kalau kamu login dengan user lain, kembalikan windows welcome screen ke keadaan semula. Biasanya windows menampilkan username yang terakhir login pada sistem. Untuk merubahnya, edit registry atau buat file .reg seperti dibawah ini lalu execute.
    Windows Registry Editor Version 5.00
    

    [HKEY_LOCAL_MACHINE\SOFTWARE\ Microsoft\WindowsNT\CurrentVersion\Winlogon]
    "DefaultUserName"="Administrator"
    Ganti Administrator dengan nama user semula.
  • Backup recent document, dan kembalikan ke keadaan semula. Harus diingat, bukan cuma windows recent document yang perlu dikembalikan ke kondisi semula tapi juga recent document pada aplikasi jika kamu membuka file. Recent document pada aplikasi biasanya di-list pada dropdown menu dari toolbar [File] dan untuk menghilangkan/mengubahnya tidak mudah. Untuk MsWord kita bisa mengghilangkannya dengan tombol (CTRL+ALT+_) setelah itu klik satu satu item di list recent file.
  • Kalo mengakses file balikan ke kondisi semula, gunakan tool untuk merubah created/modified/accessed dates misalnya FileDateChanger
  • Kalo perlu meninggalkan program yang running (misalnya trojan), buatlah program tersebut tidak terlihat. Simple application HideWin bisa dicoba.
  • Sementara ini pesan terakhir: Gunakan rootkit untuk mempermudah pekerjaan ;-)

Wednesday, October 06, 2004

Membuat file CSV

Saya pernah membuat code untuk menghasilkan file CSV (Comma Separated Value) untuk keperluan log. Tools yang saya gunakan adalah tools dari http://ostermiller.org/utils/ package com.Ostermiller.util mempunyai class-class utiliti untuk membuat atau membaca (parsing) file CSV.

Karena saya tidak ingin menggunakan semua utility yang ada package teserbut, yang saya perlukan hanya class untuk membuat file CSV maka saya copy satu file CSVPrinter.java

Menggunakan class CSVPrinter cukup mudah. Ini contoh implementasinya :
public class AuditTrailService(){


...

public OutputStream getCsvBackupFile(OutputStream os, String group) throws CATSException {
//
CSVPrinter p = new CSVPrinter(os);
try {
// Ambil data yang akan di save ke file CSV
ArrayList logs = auditTrailDB.getAllLog(group);
LogAuditTrailTO logAuditTrailTO = null;

// Komentar untuk informasi file CSV
p.printlnComment("BOF");
p.printlnComment("EQ Audit trail backup file @" + (new Date()));
p.printlnComment("");
p.printlnComment("File, group, level, time, username, status, description");

for (int i =0; i < logs.size(); i++) {
logAuditTrailTO = (LogAuditTrailTO) logs.get(i);
p.print(logAuditTrailTO.getFileName());
p.print(logAuditTrailTO.getLogGroup());
p.print(logAuditTrailTO.getLogLevel());
p.print(DateUtil.systemTime2String(logAuditTrailTO.getLogDate()));
p.print(logAuditTrailTO.getUserName());
p.print(logAuditTrailTO.getStatus());
p.println(logAuditTrailTO.getDescription());
}
p.printlnComment("EOF");
return os;
} catch (SQLException e) {
e.printStackTrace();
throw new EQException(999, "Database error. " + e.getMessage());
}
}
}
Dengan contoh method yang yang general terbut kita dapat dengan mudah membuat file CSV atau mengirimkannya ke browser dengan servlet. Dibawah ini contoh penggunaan pada struts action untuk menghasilkan file CSV dengan method tersebut,

public class AuditTrailCSVAction extends Action {

public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {

ActionErrors errors = new ActionErrors();
ActionForward forward = new ActionForward("/");

try {
// Setting header must be done before creating request's output stream
response.setContentType("text/plain");
response.setHeader(
"Content-Disposition",
"attachment;filename=logaudittrail_backup.csv");
OutputStream out = response.getOutputStream();
AuditTrailService auditTrailSvc = new AuditTrailService();
out = auditTrailSvc.getCsvBackupFile(out, "SECURITY");
} catch (Exception e) {
e.printStackTrace();
errors.add("name", new ActionError("error", e.getMessage()));
}
if (!errors.isEmpty()) {
saveErrors(request, errors);
}
return null;
}
}
Alternatif tool gratis lain yang bisa digunakan untuk membuat atau membaca file CSV bisa didapat disini. Selain itu, J-Stels Software memiliki utilitas yang lebih bagus untuk file CSV yaitu StelsCSV yang merupakan JDBC type-4 untuk text file, sehingga memanipulasi file text seperti SCV bisa dilakukan seperti manipulasi database dengan JDBC biasa. Bahkan utilitas tersebut sudah memiliki kemampuan JOIN antar file, sayangnya aplikasi terbut tidak gratis.

Tuesday, October 05, 2004

Struts bean:define error jika object null

Tips kecil dalam menggunakan struts taglib: tags-bean.

Setiap kali kita menggunakan taglib <bean:define> akan menghasilkan error jika object yang diminta adalah null. Tentu saja kita tidak mengharapkan error ini, tapi tidak ada mekanisme agar taglib tersebut mengabaikan error tersebut seperti pada tag <bean:write> yang dapat kita berikan attibute ignore="true" untuk mengabaikan error jika bean yang dimaksud tidak ada (null).

Untuk itu cek dahulu bean yang akan kita buat dengan taglib <bean:define> dengan menggunakan taglib <logic:notempty> sehingga jika memang object tersebut null maka taglib <bean:define> tidak akan dieksekusi dan hasilnya tidak terjadi pesan kesalahan jika bean tidak ada.

UI pattern dan usability

Saya pernah sekali tertarik untuk mempelajari usability dari design interface aplikasi tertutama aplikasi web. Website pertama yang sering dibaca adalah useit.com yang memberikan pencerahan terhadap bagaimana pentingnya aspek usability pada desain web dan bagaimana kita melakukannya. Apa yang diungkapkan Jakob Nielsen di website-nya kadang tidak baru tapi apa yang sudah biasa kita hadapi didepan browser. Saya pikir he is not so briliant, tapi dia tau bagaimana memilih mana yang bagus mana yang tidak, berpikir sedikit dan menggumpulkannya sebagai tulisan dan menyebutnya sebagai bapak usability.

Aspek usability pada user interface (UI) bukanlah hal yang baru. Kita dapat rasakan dengan hampir miripnya semua komponen UI yang ada pada software, dan kita terbiasa menggunakannya. Dengan menggunakan komponen yang biasa dipakai (common) berarti kita telah memberikan nilai plus pada aspek usability karena dengan komponen yang biasa digunakan user tidak perlu berkenalan lagi untuk dapat menggunakannya. Tiap software developer kenal textbox, dropdown combo, tab control dan kita cukup tau bagaimana menggunakanya dan mengkombinasikannya sehingga terbentuk UI yang lengkap dan mudah digunakan. Kita tinggal mengikuti contoh dari desain software yang ada. Walaupun desain dari segi artistik (warna, gambar) berbeda-beda tapi kita bisa merasakan kesamaan dari desain UI tersebut misalnya pada tata letak tiap komponen, interaksi antara user dan interface.

Katalog pattern untuk desain UI yang cukup lengkap, termasuk web deain, gui dan mobile user interface patter dapat kita temukan di www.welie.com. Website lain yang berisi katalog UI pattern adalah time-tripper.com/uipatterns dan "User Interface Design Patterns."

Tulisan COMMON GROUND: A Pattern Language for Human-Computer Interface Design cukup panjang dan komperhensif untuk dijadikan acuan dalam mendesain a complex interactive software artifact.

Saturday, October 02, 2004

I hate your code! (2)

Hari ini saya lihat code yang dibuat oleh orang lain. Coding-nya jelek karena beberapa hal berikut:
  • Code yang ditulis tidak konsisten, untuk hal-hal yang mirip dilakukan dengan dengan cara yang berbeda. Biasanya ini terjadi pada programmer yang baru saja belajar dan malas me-refactor code yang sudah ada. Karena tiap kali programmer awal menemuka hal yang bagus, iya akan langsung mengimplementasikannya dan yang sebelumnya dia tinggalkan begitu saja.

  • Code generator dibuat untuk mempercepat coding tapi kadang-kadang default template code generator memberikan komentar2 yang menyebalkan (karena tidak perlu). Template untuk code generator sebelum mulai coding harus diubah, pekerjaan sekali tapi kadang tidak dilakukan dan membuat source code kita kotor.

  • Komentar pattern. Saya menemukan komentar (javadoc) tentang pattern yang berhubungan dengan suatu class menjadi komentar class tersebut. Tentu saja akan muncul pada dokumentasi api. Ini contoh kontar yang dibuat:

    Responsibilities : Bla bla bla
    Collaborations : Bla bla bla
    Dependencies : Bla bla bla
    Applied Patterns : Bla bla bla

    Menurut saya ini jelek. Biarkan dokumentasi pattern disimpan di dokumentasi software design. Hal ini karena pattern biasanya melibatkan banyak kelas tidak satu class (pattern Singelton termasuk pattern yang hanya melibatkan satu kelas) jadi pattern tidak berasosiasi kuat dengan satu class. Saya tidak tau dari mana dia mendapat ide untuk membuat komentar seperti itu. Ada yang pernah membuat komentar seperti itu?

Struts: Cancel button

Struts punya mekanisme untuk mendeteksi action dari cancel button. Dengan cara kita sendiri, mudah untuk membuat cancel button yang berfungsi saat kita membatalkan suatu halaman/form.

Jika kita tahu mekanisme yang sudah ada, kita tidak perlu repot lagi. Struts mempunyai taglib html <html:cancel> yang bisa kita gunakan untuk cancel button. Jika kita membuat cancel button dengan tag tersebut tanpa meng-overide attribute "onclick" dan "property" maka kita akan mendapatkan kemudahan dari pemrosesan pembatalan. Proses pembatalan suatu form yaitu [1] tidak dilakukannya validasi pada form walaupun cancel button sebenarnya melakukan POST seperti halnya button submit dan [2] dengan pendeteksian yang mudah disisi struts-action, kita bisa menangani aksi cancel ini berbeda dengan aksi submit.

Contoh sebuah button cancel :
  <html:cancel>Cancel</html:cancel>
Tag tersebut akan menghasilkan html seperti ini:
  <input type="submit" name="org.apache.struts.taglib.html.CANCEL" value="Cancel" onclick="bCancel=true;">
Dan kita bisa mendeteksi pada struts-action dengan cara seperti ini:
  public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {

if (isCancelled(request)) {
// do something here
...
return (mapping.findForward("success"));
}
}

Friday, October 01, 2004

I hate your code!

Saya sudah banyak ikut bergabung dalam project IT, tentu saja bukan project sendirian. Setiap project pasti melibatkan orang lain walaupun itu project yang kecil misalnya cuma sekedar membuat web site. Actually saya belum pernah membuat website yang benar2 simple. Sekecil apapun project IT yang saya kerjakan mininal melibatkan art designer, jadi pekerjaan bisa dijalankan dengan 2 orang. Saya sebagai architect dan developer dan seorang lagi sebagai art designer.

Dengan dua orang saja yang punya fungsi yang jelas berbeda dalam satu project tidak sulit untuk membuat project berjalan lancar. Tentu saja lebih sedikit konflik.

Beberapa project melibatkan banyak orang dengan role yang sama, misalnya developer atau programmer. Ketika tidak ada hal-hal standar yang disepakati bersama, siap-siap saja untuk gagalnya project atau paling tidak jadi project yang menjengkelkan.

Beberapa orang mungkin bekerja cepat, tapi pekerjaannya jelek. Yes, his code is run but..it's suck. Artikel "Humor: Why your code sucks" sama sekali bukan humor, even the discussion is. Point-point dari artikel tersebut totally right. Saya sendiri benci dengan code yang jelek, walaupun mungkin code saya sebenernya jelek (i can't count my own code).

Bukan karena code kita hanya akan digunakan hanya oleh diri kita sendiri lalu kemudian kita bisa seenaknya coding tanpa membuatnya mudah dibaca dan dimengerti.

Kenapa ini harus terjadi di project saya sekarang... :(

Bagaimana JVM bekerja?

Website ARITMA punya bahan-bahan dan link-link yang bagus untuk topik JVM di Java Corner-nya. Ada preview buku Inside the Java Virtual Machine, juga aplet-aplet simulasi JVM, garbage collector, dll.


Struts Validator: ActionForm menjadi ValidatorForm

Menggunakan struts tanpa validasi cukup mudah, menggunakan framework validasinya Atruts ternyata memperudah pekerjaan. Tapi tunggu, saya dapat masalah ketika struts form-bean harus berubah dari subclass ActionForm mejadi subclass dari ValidatorForm atau ValidatorActionForm.

Saya biasa membuat property dari form-bean dengan variabel-variabel seperti Integer, Double, String, Long dan bahkan kadang-kadang menggunakan primitive variables. Semuanya tidak ada masalah. Jika suatu input karakter harus jadi null pada form-bean karena input tersebut di-set pada property form-bean yang bertipe Integer, saya cukup senang dengan hal itu. Setelah saya menggunakan validator framework, ternyata muncul masalah yaitu saya harus mengubah semua property form-bean saya menjadi String.

Hal ini karena validator akan menganggap input dari client adalah null jika input tidak match dengan tipe varibel form-bean. Misalnya kita membuat input "Foo" yang harus diset pada property "age" yang bertipe Integer, maka struts variabel "age" akan berisi null untuk kemudian dilakukan validasi. Tentu saja ini tidak bagus, karena dengan dua aturan validasi misalnya "varibel tersebut diperlukan (required)" dan "varibel tersebut harus integer" maka komentar error yang muncul adalah komentar required bukannya komentar error kesalahan tipe data.

Jadi validator framework perlu mendapatkan karakter input sesuai dengan input data dari client. Dan hal ini hanya dapat diperoleh jika 'semua' property pada form-bean bertipe String. Paling tidak semua property yang butuh divalidasi.

Do I miss something in Struts?

Wednesday, September 29, 2004

JSF jelek?

Matt Raible yang berpengalaman dengan web framework seperti Struts, Spring MVC, Webwork dan Tapestry mencoba JSF 1.1 (dengan menggunakan Sun's Reference Inplementation) dan berkesimpulan bahwa JSF adalah yang terjelek. Pengalamannya dengan JSF dia tuliskan dalam blognya "My JSF Experience"

Sebuah riset yang membandingkan antara beberapa teknologi dan memberikan kesimpulan bahwa yang satu lebih baik dari yang lain selalu menjadi topik yang menarik,
seperti Windows vs Linux, Java vs .NET dan lain-lain. Tulisan Matt pun jadi perdebatan yang menarik, kita bisa baca hasil diskusi topik ini di TSS.

Tulisan dari David Geary "A reply to Matt Raible's article 'My JSF Experience'" muncul menanggapi tulisan tersebut. Satau tulisan yang bagus dan wajib dibaca setelah membaca tulisan Matt.

Buat saya JSF tetap menarik karena model desainnya event-driven dan action diimplementasi dalam bentuk POJO dan tentu saja mudah digunakan hanya jika menggunakan tool IDE.

Struts atau JSF atau Struts+JSF?

Sebagai java web developer, kadang kita dibingungkan dengan banyaknya web MVC framework yang telah ada. Kemudian tiba-tiba Sun membuat spesifikasi framework standar aplikasi web yaitu JSF (JSR-127), ini membuat kita untuk belajar teknologi baru, membandingkannya untuk kemudian memilih mana yang tepat untuk kebutuhan kita.

Craig McClanahan, orang dulu pertama kali membuat Struts dan salah satu lead dari tim spesifikasi JSF, menulis dalam blog-nya tentang kedua teknologi web tersebut: "Struts or JSF? Struts and JSF?." Untuk aplikasi yang sudah menggunakan Struts menurutnya sebaiknya untuk view layer diganti dengan JSF component tags, untuk menambah kemampuan user interface (JSF memang fokus pada view layer dalam terminologi framework MVC).

Untuk aplikasi baru, dia menyarankan mempertimbangkan hal-hal berikut:

  • Evaluate the two technologies individually, to see if they satisfy your requirements.

  • If one or the other technology is sufficient, go ahead and use it (it's easier to learn and use one technology rather than two where possible); keeping in mind, however, the caveats about Struts HTML tags mentioned above.

  • If your requirements include unique features supported only by Struts (such as Tiles or client side validation support), feel free to use the two frameworks together.


Tuesday, September 28, 2004

Standar baru data persistance untuk J2SE dan J2EE

Dalam artikel "A Letter to the Java Technology Community" Sun memberitakan bahwa mereka akan menginisialisasi sebuah spesifikasi baru untuk data persistance object yang merupakan mix antara EJB (JSR-220) dan JDO (JSR-243).

Model data persistance tersebut akan dibuat berbasiskan POJO (Plain Old Java Object) sehingga lebih sederhana. Diharapkan ini akan menjadi sebuah model data persistance standar untuk J2SE dan J2EE.

Monday, September 27, 2004

Web: PRG Pattern

Post/Redirect/Get (PRG) Pattern adalah pattern untuk solusi masalah duplikasi submit. Poin penting pada pattern ini adalah:
  • Jangan pernah menampilkan halaman hasil respon dari POST
  • Tampilan halaman harus selalu respon dari GET
  • Gunakan REDIRECT setelah request POST menjadi request GET
Lebih jelasnya baca di artikel "Redirect After Get" dan diskusi tentang pattern ini di TSS.
Lihat juga contoh implementasi dan source code dengan menggunakan Struts framework di RPG pattern working example

Saturday, September 25, 2004

Java: Hati-hati dengan FileOutputStream

Posting blog "How I hacked Jroller.com" ini menjelaskan bagaimana kita bisa mengupload file yang berbahaya dengan memanfaatkan bug pada kode program. Triknya sebenarnya simple yaitu menggunakan null byte pada nama file yang akan diupload. Dibawah ini contoh sederhana bagaimana nama file trojan.jsp\000.gif dapat berubah menjadi trojan.jsp
public class Test {


public static void main(String[] args) {
String uploadedFileName = "trojan.jsp\000.gif";
byte[] buffer = new byte[8192];
int bytesRead = 0;
try {
InputStream stream = new FileInputStream("C:\\test.log");

// Save a file with strange file name
OutputStream bos = new FileOutputStream("C:\\"+ uploadedFileName);
while ((bytesRead = stream.read(buffer, 0, 8192)) != -1) {
bos.write(buffer, 0, bytesRead);
}
bos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Jadi hati-hatilah dengan kode program kita, validasi yang benar akan menghindarkan kita dari lubang keamanan.

Javascript: Avoid duplicate submit

Menghindari duplikasi pengiriman form bisa diatasi dengan menggunakan Synchronizer Token Pattern seperti di posting sebelumnya. Tapi dapat juga dilakukan dengan menggunakan javascript.

[1] Sebelum form dikirum (submit), check dulu dengan fungsi javascript checkSubmit()
<form action="myAction.do" method="post" onsubmit="return checkSubmit();">

Kode javascript :
<script language="javascript">

var checkSubmitFlg = false;
function checkSubmit() {
if (checkSubmitFlg == true) {
return false;
}
checkSubmitFlg = true;
return true;
}
document.ondblclick = function docondblclick() {
window.event.returnValue = false;
}
document.onclick = function doconclick() {
if (checkSubmitFlg) {
window.event.returnValue = false;
}
}
</script>

[2] Cara lain adalah dengan menggunakan bantuan tag input tipe image :
  <form action="myAction.do" method="post"

onsubmit="getElById('submitInput').disabled = true; return true;">

<input type="image" id="submitInput" src="images/buttonOK.gif" border="0" />

</form>

Struts: Synchronizer Token Pattern

Synchronizer Token Pattern digunakan untuk mengatasi masalah multiple/duplicate submit pada suatu halaman yang memiliki form input.

Submit berulang-ulang pada suatu halaman dari form input biasanya terjadi karena sengaja atau tidak sengaja. Dengan sengaja misalnya user mencoba melakukan posting berkali-kali dengan data yang sama atau secara tidak sengaja misalnya user meng-click tombol submit berkali-kali atau melakukan refresh pada halaman setelah dia post/submit dari halaman form input. Kedua kasus tersebut tentu saja tidak diharapkan, untuk itu kita perlu melakukan trik untuk dapat mencegah terjadinya multiple submit tersebut.

Salah satu solusinya adalah dengan menggunakan Synchronizer Token Pattern, caranya dengan memberikan suatu tanda (token) untuk setiap transaksi (aksi submit dari user). Transaksi dimulai ketika web server akan menampilakan halaman form input. Form input tersebut diberi tanda dengan varibel tersembunyi (hidden input) dengan nilai tertentu biasanya nomor random. Nilai tersebut disimpan di server dalam session milik user. Ketika user melakukan submit pada form, server akan mencocokan nilai token yang dikirim dari form dengan yang ada di session user. Jika nilai tersebut sama maka server akan melanjutkan proses dan me-reset kembali nilai token dan menyimpannya kembali di session user. Jika kedua nilai tersebut berbeda berarti user mengirimkan data yang berbeda dari yang diharapkan server, artinya server akan me-reject data yang dikirim oleh user.

Dengan Struts, kita dapat mengimplementasikan Synchonizer Pattern dengan mudah. Sebelum halaman dengan form input dipanggil, pada action panggilah saveToken(request) untuk menbuat nilai token baru dan menyimpannya di session. Halaman form tidak perlu penambahan apa2, hanya pastikan form yang digunakan menggunakan tag <html:form>. Dengan cara seperti itu form akan memiliki input dengan tipe hidden yang otomatis dibuat oleh struts:


<input name="org.apache.struts.taglib.html.TOKEN" value="d3977d02b2490a92e6f8f22e8a0777b4" type="hidden">

Sedangkan pada action pemroses dari form tersebut kita lakukan pengecekan token sbb:

public ActionForward deleteQuotation(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {

ActionErrors errors = new ActionErrors();
ActionMessages messages = new ActionMessages();

// Check if token is valid
if (!isTokenValid(request)) {
errors.add(ActionErrors.GLOBAL_ERROR, new ActionError("error.transaction"));
saveErrors(request, errors);
return mapping.findForward("transactionError");
}

try {
// Call business proces here
...

// Reset token
resetToken(request);

messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("msg.FooSuccess"));
saveMessages(request, messages);
} catch (Exception e) {
e.printStackTrace();
errors.add(ActionErrors.GLOBAL_ERROR, new ActionError("error", e.getMessage()));
}
if (!errors.isEmpty()) {
saveErrors(request, errors);
}
return mapping.findForward("submitSuccess");
}

Wednesday, September 22, 2004

Struts: Release terbaru 1.2.4 (Cepat amat!)

Setelah Struts release General Availability (GA) 1.2.2 muncul tanggal 31 Agustus, belum sebulan per 20 Sepetember sudah dirilis Struts realease 1.2.4.

Struts memang dalam mode maintenance dalam beberapa bulan terakhir ini, banyak perombakan disana-sini. Versi 1.2.2 sepertinya terlalu cepat untuk dirilis sebagai GA. Versi 1.2.2 hanya support JDK1.4 (misalnya terdapat penggunaan kode Boolean.valueOf(...)), untuk versi 1.2.4 sudah bisa di-build dengan JDK 1.3

Baca saja relese notes untuk detail perubahan dan penambahan pada Struts versi baru.

Websphere vs Visual Studio .Net

MiddlewareREASEACH membuat perbandingan antara J2EE development dengan RDD (Rational Rapid Developer), J2EE developmet dengan Websphere dan .Net development dengan VisualStudio .Net (VS.NET). Hasil lengkap, source code bisa dihat link berikut:

Comparing Microsoft .NET and IBM WebSphere/J2EE: A Productivity, Performance, Reliability and Manageability Analysis

Berita Microsoft: Study Shows Visual Studio .Net Tops WebSphere jelas-jelas mempromosikan VS.NET. Katanya dari hasil studi tersebut VS.NET lebih unggul dibanding yang lainnya baik baik dari segi productivity, performance dan bahkan cost.

Sebelum memberi kesimpulan sendiri, sebaiknya dibaca komentar2 dari berita ini di TSS.com dan TSS.net Dari salah satu komentar diketahui bahwa applikasi J2EE pada perbandingan tersebut menggunakan plain vanilla J2EE (tanpa framework apapun) yang jelas jarang sekali terjadi, tapi... tapi... baca saja sendiri komentar2nya.

Yang jelas, hasil ini tidak merepresentasikan hal sebenarnya apapun hasilnya karena studi yang komprehensip sulit didapat untuk membandingkan dua hal yang jelas-jelas berbeda.

Struts: BlobAction

Sudah jadi hal yang biasa kita melakukan pengambilan binary data (BLOB) baik itu dari database ataupun file system. Di mailing list strust, seseorang mengirimkan email yang menyarankan menambahkan BlobAction (action class untuk mengambil binary data) pada struts, tentu saja sarannya tidak diterima karena fungsi tersebut terlalu spesifik. Tapi kodenya tentu saja baik untuk diliat sebagai best-practice.

Email dan code untuk BlobAction bisa dilihat disini, tapi sebaiknya dilakukan refactoring sesuai saran dari email berikutnya, terutama dua komentar terakhirnya :

* Your approach is not very flexible. You may not always want to

read the data completely into memory before writing it to the
response.
* BTW, it's a good idea to call response.reset() and, if possible,
to set the content length before writing to the OutputStream.

Tuesday, September 21, 2004

Link: #develop : Opersource IDE untuk C# atau VB.Net

#develop (baca: SharpDevelop) adalah IDE opensource (lisensi GPL) yang berjalan pada platform .NET. Saat ini telah dirilis versi 1.0 (9/11/2004), bisa didownload di

http://www.icsharpcode.net/OpenSource/SD/Download/

Kalo belum punya .Net framework, download disini :

Microsoft .NET Framework Version 1.1 Redistributable Package

Saturday, September 18, 2004

Programming: Closures / Blocks

Essentially a closure is a block of code that can be passed as an argument to a function call.

Java punya inner class, C# punya delegate tapi kedunya berbeda, Martin Fowler menjelaskan konsep pemrograman "Closure" ini disini.


Struts: Yet another best practices

Di artikel ini Struts best practices: Build the best performing large applications dibahas beberapa tips solusi yang biasa dihadapi saat memprogram dengan struts diantaranya :
  • Tampilan dengan elemen/komponen html yang dinamis
  • Mengamankan file JSP
  • Pengkategorian error
  • Validation of service requester (authentication)
  • Application security (authorization)
  • Prepopulation
  • Stack maintenance (for bread crumbs)
  • Masalah Context-related
  • Form-bean scope
  • Implementasi Data transfer object
  • Exceptions
  • Action chaining
Tulisan yang bagus sayang kurang contoh code.



Friday, September 17, 2004

Struts: Menghindari error kehilangan list ketika validasi gagal (prepopulation problem)

Seringkali kita membuat object List atau Collection dari data yang tersimpan di database untuk dropdown-list (combo box) pada halaman html dengan cara memanggil method pada business layer. Pemanggilan method yang menghasilkan List tersebut dilakukan oleh struts Action kemudian disimpan pada scope request.
public ActionForward execute(ActionMapping mapping, ... ) {


List currencyList = CurrencyService.getAllCurrency();
request.setAttribute("currencyList ", currencyList);
...

}
Dihalaman jsp kemudian kita membuat script seperti ini:
  <html:select property="currencyId">

<html:options collection="currencyList" property="lookupId" labelproperty="codeAndDescription"/>
</html:select>
Menyimpan list di scope request saat eksekusi Action akan menjadi masalah jika validasi pada struts form-bean menghasilkan error dan input mapping adalah halaman jsp yang sama dimana diperlukan list untuk dropdown combo. Masalahnya adalah list tidak tersedia di scope request karena setelah validasi mengghasilkan error, Action tidak dieksekusi.

Solusi yang biasa saya lakukan adalah dengan meyimpan list di scope request jika method validate() di form-bean menghasilkan error selain juga di Action.
public ActionErrors validate(ActionMapping map, HttpServletRequest req) {

ActionErrors errors = new ActionErrors();
...
if (!errors.empty()) {
//
List currencyList = CurrencyService.getAllCurrency();
request.setAttribute("currencyList ", currencyList);
}
}
Tentu saja ini kurang baik, karena adanya duplikasi code di form-bean dan di Action. Cara lain yang lebih baik adalah meyimpannya di method reset() pada form-bean sehingga tidak terjadi lagi duplikasi, karena method reset() akan dipanggil setiap kali sebelum form dibuat. Cara kedua ini kurang elegan karena melakukan pemanggilan proses bisnis pada form-bean yang menyulitkan maintenance.

Agar lebih baik, buatlah sebuah class facade dengan method-method static untuk melakukan hal tersebut:
public void reset(ActionMapping arg0, HttpServletRequest request) {

LookupUtility.setCurrencyList(request);
...
}
...akhirnya, saya menemukan artikel terkait dengan tulisan ini (ide tulisan ini sudah ada sebelum artikel dibawah ini ditulis, agak aneh kenapa masalah yang biasa terjadi tidak banyak ditulis orang padahal artikel struts begitu banyak di internet):

How to make sure request scoped lists persist when validation fails

Tulisan lain yang membahas masalah ini: Prepopulation - the three action edit

Javascript: Membuat element pada html page on-the-fly

Ini termasuk most wanted script buat saya: membuat element input pada suatu form pada dokument html.
   _form = document.userListForm;

var method = document.createElement('INPUT');
method.setAttribute('name','method');
method.setAttribute('type','hidden');
method.setAttribute('value','Delete');
_form.appendChild(method);
Pada contoh tersebut, kita membuat sebuah element form input dengan type hidden yang sebelumnya tidak ada. Ini seperti kita membuat pada saat runtime. Method createElement() pada dasarnya digunakan untuk membuat element html apa saja (tergantung browser). Element ini memiliki satu paramater yaitu string tag html, misalnya div, button, image atau yang lainnya.

Referensi: W3C DOM Level 1

Tuesday, September 14, 2004

Link: Java open source

Link ini baru saya temukan, bagus untuk mencari open source project berbasis java:

http://java-source.net/

Biasanya saya cari di sini: sourceforge.net, freshmeat.net dan tentu saja google.com

Memanfaatkan CacheRowSet

Jika kita sering JDBC, pasti sudah familiar ResultSet. Jika Connection, atau Statement yang menghasilkan ResultSet kita close() secara otomatis ResultSet akan close dan kita tidak bisa menggunakan objek ResultSet untuk mengambil data. Begitu juga ketika object ResultSet tersebut di-overide. Hal ini terjadi karena sebenarnya suatu ResultSet hanya merupakan suatu pointer (cursor) yang merujuk pada data sebenarnya di memori, jadi ResultSet tidak menyimpan data.

Dengan CachedRowSet permasalahan itu bisa teratasi, kita bisa membawa object CachedRowSet untuk mengambil data dari hasil query walaupun Connection atau Statement telah di-close(). Bahkan kita dapat melakukan update data langsung lewat CachedRowSet. Ini memudahkan perkerjaan kita karena kita tidak perlu lagi data transfer object jika pekerjaan kita ingin lebih se

CachedRowSet adalah interface meng-extends javax.sql.RowSet, ResultSet, Joinable. Jadi jika kita sudah familiar dengan ResultSet akan mudah menggunakan CachedRowSet.

CachedRowSet mendukung event notification, sehingga kita bisa dengan mudah mengetahui jika cursor bergerak (move), atau terjadi perubahan data.

CachedRowSet yang berawal dari JSR 114, merupakan standar di JDBC 2.0 dan telah masuk dalam standar API di Java 1.5 (Tiger). Jika kita menggunakan java versi 1.4.2 kita bisa menggunakan reference implementation.

Tiga subinterface yang juga sangat bermanfaat adalah FilteredRowSet, JoinRowSet, WebRowSet. Dengan FilteredRowSet kita dapat melakukan filtering data pada RowSet yang sudah kita peroleh tanpa perlu melakukan query lagi ke database. Sedangkan JoinRowSet bermanfaat untuk melakukan penggabungan lebih dari satu RowSet dengan tipe-tipe join database yang sudah kita kenal seperti INNER JOIN, LEFT/RIGHT OUTER JOIN, INNER JOIN, FULL JOIN, CROSS JOIN. Yang terakhir WebRowSet mempermudah kita mengeluarkan output database dalam bentuk XML dan memanipulasinya.

Dokumentasi API dari interface ini cukup baik (ada contoh penggunaannya): http://java.sun.com/j2se/1.5.0/docs/api/javax/sql/rowset/CachedRowSet.html

Tutorial JDBC dari Sun bagian CachedRowSet (ada contoh implementasi untuk distributed application/EJB)

Friday, September 10, 2004

Best Practices

Blog ini akan penuh dengan best practices, tip dan trik. Kenapa?

Saat kita melakukan development suatu sistem hanya dengan dasar pemrograman (bisa memprogram) saja tidak cukup. Apalagi jika menggunakan suatu framework baru, kita tidak hanya perlu belajar bagaimana menggunakannya tapi juga bagaimana menggunakan framework tersebut secara baik dalam arti efektif juga efisien. Oleh karena itu best practices sangat diperlukan. Best practice tidak akan didapat ketika kita pertama kali melakukan permrograman.

Best practice sering didaptkan justru karena kita telah sering melakukan hal-hal yang sama, melakukan tes kemudian mendapatkan masalah. Best practices bisa dianalogikan dengan dengan design pattern dan sering ditemukan setelah kita melakukan beberapa kali refactoring kode.

lebih dari itu best practice dalam proses development tidak hanya berlaku pada kode program saja. Tapi lebih dari itu best practices juga menyangkut proses manajement proyek. Karena pentingnya best practices, maka kita perlu mendokumentasikannya. Selain bermanfaat untuk diri sendiri, dokumen best practice akan berguna bagi pemula untuk dapat dengan cepat belajar dari pengalaman orang lain.

Topik yang menarik kan? Saya akan cari sumber bacaan untuk ini, dan mari kita sharing.

Wednesday, September 08, 2004

Servlet tips: Menghentikan rantai Filter? jangan lupa untuk return void

Kalau kita perlu menghentikan rantai (chain) Filter, misalnya dengan forwarding ke JSP, maka jangan lupa untuk return void, sehingga FilterChain.doFilter() tidak dieksekusi. Jika hal ini tidak dilakukan, lihat saja errornya!

Ini contohnya:

public class LoginFilter implements Filter {
public void doFilter(
ServletRequest req,
ServletResponse resp,
FilterChain chain)
throws ServletException, IOException {

LoginSession loginSession = WebUtility.getLogin((HttpServletRequest) req);
if ( loginSession == null) {
req.setAttribute("message","Login Required: Your session is expired or you are not login.");
((HttpServletRequest) req).getRequestDispatcher( "/errorNotLogin.jsp").forward(req, resp);
return;
}
chain.doFilter(req, resp);
}
public void init(FilterConfig config) throws ServletException {
}
public void destroy() {
}

}

Tuesday, September 07, 2004

Servlet tips: set session=false untuk performansi

Servlet tips: Gunakan <%@ page session="false">di halaman JSP

File JSP by-default akan membuat HttpSessions. Jika kita tidak menggunakan HttpSession pada halaman JSP maka dengan memberikan <%@ page session="false"%>kita akan meningkatkan performansi (walaupun kecil). Ini juga tergantung application server-nya ;)

referensi

Servlet tips: Replikasi HttpSession pada lingkungan distributed web application

Dari artikel: Java theory and practice: State replication in the Web tier

Beberapa web application server (servlet container) yang mensupport clustering atau melakukan replikasi data user (yang biasa disimpan pada session) dengan melakukan serializing objek yang berada di HttpSession yang kemudian ditransfer ke node cluster yang bersangkutan sehingga node tersebut dapat melakukan pemrosesan tersendiri terhadap request dari client. Begitu pula pada sistem load balancing.

Ada tiga pendekatan (cara) replikasi objek session yaitu dengan :
- JDBC-based replication
- File-based replication
- Memory-based replication

untuk memilih opsi mana yang akan kita pilih memperhitungkan/membandingkan cost yang dibutuhkan dari ketiga cara tersebut (web application server yang bagus biasanya mensupport 3 cara replikasi tersebut).

Beberapa tips untuk meningkatkan performansi:
  • Buatlah objek yang disimpan di session seminimal mungkin.
  • Jangan mem-by-pass setAttribute(). Jika kita telah merubah objek pada session lakukan setAttibute() untuk menyimpannya kembali di session, kalau tidak data perubahan tidak akan tersimpan.
  • Gunakan fined-grained object (object yang kecil) yang akan disimpan di atribut session. Ini akan mempercepat proses serializing objek saat di replikasi.
  • Jika tidak digunakan lagi segera invalidate objek. Ini akan menghemat memori karena object tidak menunggu dihilangkan saat session timeout.
  • Usahakan session tetap bersih. Buang session jika tidak lagi diperlukan, sehingga tidak ada lagi yagn perlu di replikasi.

Java New I/O API


Java 2 Standard Edition 1.4 memiliki feature baru yaitu New I/O API (package java.nio) yang memberikan kemampuan performasi yang tinggi dan scalable untuk operasi input/output (baca tulis) files dan sockets, regular expressions, decoding/encoding character sets, in-memory mapping, dan locking file.

New I/O api menambahkan SocketAddress dan InetSocketAddress di package java.net, interface java.lang.CharSequence dan 6 package baru yaitu:

java.nio,
java.nio.channels,
java.nio.charset,
java.nio.channels.spi,
java.nio.charset.spi,
java.util.regex

"spi" singkatan dari "service-provider interface.

Jika kita membutuhkan high performance network I/O seperti router/server yang harus menerima koneksi bersamaan yang banyak, maka kita dapat menggunakan fasilitas API tersebut. New I/O juga sering disebut Non-blocking I/O karena kemampuannya dalam menangani koneksi yang banyak tanpa terjadi blocking I/O.

Cara yang biasa untuk mengangani koneksi I/O bersamaan adalah dengan meng-hanlde tiap koneksi oleh thead tersendiri. Hal ini dapat mengakibatkan banyaknya thread yang menghabiskan resource, menimbulkan kompleksitas singkronisasi antar thread hingga menimbulkannya deadlock.

Prinsip kerja New I/O ini adalah multiplexing dari koneksi I/O yang bersamaan. Beberapa koneksi yang direpresentasikan oleh SocketChannel di-handle oleh sebuah Selector, selector akan melakukan mekanisme baca/tulis dari tiap channel secara serial (multiplexing) dengan cara menggambil buffer. Tiap buffer yang diambil Selector yang merupakan bagian dari bagian data yang dikirim oleh client disebut key atau SelectionKey. Key tersebut kemudian dikirim ke pemroses atau server.

Algotitma non-blocking server adalah sebagai berikut:

create SocketChannel;
create Selector
associate the SocketChannel to the Selector
for(;;) {
waiting events from the Selector;
event arrived; create keys;
for each key created by Selector {
check the type of request;
isAcceptable:
get the client SocketChannel;
associate that SocketChannel to the Selector;
record it for read/write operations
continue;
isReadable:
get the client SocketChannel;
read from the socket;
continue;
isWriteable:
get the client SocketChannel;
write on the socket;
continue;
}
}
Untuk lebih detailnya, baca saja artikel-artikel berikut:

Monday, September 06, 2004

HTTP watcher plugin for browser


Tools dibawah ini saya pakai untuk melihat data HTTP yang dikirim atau diterima oleh browser:

1. ieHTTPHEaders plugin yang paling bagus untuk Internet Explorer, karena sederhana (simple) dan gratis. Download!

2.Untuk pengguna mozilla atau firefox, bisa menggunakan LiveHTTPHeaders

Tools seperti ini penting untuk web developer, karena kadang kita tidak teliti sehingga menyebabkan kesalahan pada penamaan komponen form yang menyebabkan kesalahan pada nama parameter yang di-submit. Dengan alat bantu ini kita bisa lihat semua parameter yang dikirim dari browser ke web server.

Friday, September 03, 2004

Struts: Yang baru dan berubah di versi 1.2

Struts sudah merilis versi barunya 1.2 dengan perubahan dan tambahan yang bisa dilihat di release notes-nya.

Beberapa highlight (perubahan yang tidak signifikan karena jarang saya gunakan atau tambahan feature yang tidak menarik, tidak saya tulis):

  • Kita bisa menggunakan wildcards pada action-mappings. Lihat struts user guide bagian action mapping untuk mepelajarinya
  • Penambahan package Struts-Chain yang masih dalam eksperimen untuk menggantikanRequestProcessor dengan commons-chain (base API untuk implemntasi "Chain of Responsibility" pattern)
  • DTD baru untuk file konfigurasi: struts-config_1_2.dtd
  • Penambahan method pada class Action: getErrors, getMessages, addErrors, and AddMessages .
  • Method deprecated perform() pada class Action dan subclass-nya dihilangkan.
  • Perubahan ActionError menjadi ActionMessage, ActionError tidak dihilangkan tapi sebaiknya tidak digunakan.
  • Lihat contoh untuk aplikasi upload dan validator
  • Attribute name, scope, type dihilangkan pada FormTag
  • Penambahan attribute "module" pada IncludeTag, ImgTag, LinkTag, and RewriteTag, untuk memudahkan cross-linking antar modul
  • Penmbahan custructor pada ActionForward untuk membuat instance baru dari instance lain: ActionForward(ActionForward copyMe)
  • saveErrors(HttpServletRequest, ActionErrors) pada class Action diganti dengan saveErrors(HttpServletRequest, ActionMessages)
  • Metod getResources() dihilangkan dari Action, ActionException (Kenapa ya?)
  • Penambahan method cancelled(...) pada DispatchAction, LookupDispatchAction, dan MappingDispatchAction untuk mengangani ketika tombol cancel di-submit
Sudah cukup sepertinya. Waktunya download

Javascript for checked all html checkbox

Kalo kamu web developer pasti sering membuat list (table) yang menampilkan item dalam banyak baris dengan checkbox, dan membuat satu checkbox yang berfungsi untuk memilih semua item tersebut. Contoh halaman seperti itu bisa kita lihat di "Check Mail"-nya yahoo yang berfungsi untuk memilih item email yang akan diproses, misalnya dihapus.

Yang sering terlewat ketika kita membuat halaman seperti itu adalah, pengecekan apakah item dengan checkbok muncul hanya ada satu atau lebih dari satu atau bahkan tidak ada. Kita biasanya membuat satu chekbox yang berfungsi untuk memilih semua item tersebut selalu tampil walaupun tidak ada item/checkbox dalam list. Biasanya yang terjadi adalah script yang kita buat error karena kita lupa untuk mengecek apakah ada atau tidak, atau jika ada jumlahnya satu atau lebih dari satu.

Karena kita tidak tahu berapa record/item data yang akan muncul, maka di script yang kita buat perlu mengecek apakah ada tidaknya checkbox dan jumlah checkbox. Pengecekan jumlah checkbox dilakukan karena pada javascript penanganan satu checkbox dengan array checkbox (lebih dari datu) berbeda.

Dibawah ini contoh suatu form dengan sebuah checker yaitu checkbox yang berfungsi untuk mengmilih semua checkbox yang bernama userIds.

<form name="listUserForm">
<input name="checker" onclick="checkAll(document.listUserForm.userIds, this)" type="checkbox">
<input name="userIds" type="checkbox">
<input name="userIds" type="checkbox">
<input name="userIds" type="checkbox">
</form>
Script untuk form diatas seperti ini:

<script language="javascript">
function checkAll(checklist, checker) {
if (checklist) {
if (checklist.length > 0) {
for (i = 0; i < checklist.length; i++) {
checklist[i].checked = checker.checked;
}
} else {
checklist.checked = checker.checked;
}
}
}
</script>

Dengan pengecekan (checklist.length > 0) script kita aman dari bug.

Thursday, September 02, 2004

UMLGraph: Tools untuk membuat diagram UML berbasis teks


Saat ini UMLGraph hanya bisa membuat class diagram dan sequence diagram. Kita bisa membuat class diagram lewat yang dispesifikasikan di javadoc. Untuk membuat class diagram program ini menggunakan declarative language yang mudah untuk dimengerti, sedangkan untuk sequence diagram-nya menggunakan imperative language seperti ini:


# Define the objects
object(O,"o:Toolkit");
placeholder_object(P);
step();

# Activation and messages
active(O);
message(O,O,"callbackLoop()");
create_message(O,P,"p:Peer");
message(O,P,"handleExpose()");
active(P);
return_message(P,O,"");
inactive(P);
destroy_message(O,P);
inactive(O);

# Complete the lifeline of O
step();
complete(O);


Sulit dibaca kan? Lebih langkapnya lihat saja website UMLGraph

Tool lain untuk membuat sequence diagram SEQUENCE, jAdvice SEQUENCE

Produk kecil tersebut mungkin jauh dibandingkan dengan XDE, RationalRose, Together dll tapi tetap menarik untuk dicoba.

Tuesday, August 31, 2004

OSMM (Open Source Maturity Model)

OSMM (Open Source Maturity Model) adalah model proses untuk membantu suatu organisasi dalam mengimplementasikan open source software dengan cara mengevaluasi produk open source yang akan digunakan. OSMM memang dibuat lightweight (sederhana) sehingga produk open source dapat dievaluasi dengan cepat. OSSM menilai maturity level dari produk dengan menggunakan 6 elemen dari produk dengan menggunakan pembobotan sbb:
Software              4
Support 2
Documentation 1
Training 1
Integration 1
Professional services 1
Total 10
Links :

Contoh aplikasi software pattern untuk non-software


Software pattern design ternyata dapat diaplikasikan pada dunia non-software.
Lihat aja contoh-contohnya disini :

Catalog of Non-Software Examples of Design Patterns

Bagus juga untuk mengingat/mengerti ide dari design pattern tersebut.

Followers