Memakai Reverse Ajax “Comet” Dengan Spring Web MVC 3.2

Hujan turun tanpa henti di malam yang ceriah ini.   Karena hari ini adalah hari terakhir di tahun 2012.  Dan tulisan ini akan menjadi tulisan terakhir di tahun 2012.  Selamat merayakan tahun baru dan selamat datang, 2013!  Kode program terakhir yang saya ubah di tahun 2012 berkaitan dengan sebuah aplikasi web yang saya buat dimana tampilannya seperti berikut ini:

Permintaan Perubahan

Permintaan Perubahan

Halaman tersebut menampilkan data termasuk status data yang ada. Perubahan status data, seperti “Belum Disajikan” menjadi “Sudah Disajikan” dilakukan oleh pengguna lain di komputer lain. Perubahan ini perlu diperbaharui oleh halaman tersebut.

Tetapi yang terjadi adalah bila pengguna membuka halaman ini, maka sampai selama-lamanya halaman akan terlihat sama, walaupun pengguna lain telah men-update status data.   Informasi yang ditampilkan menjadi tidak up-to-date lagi.

Lalu bagaimana cara memperbaharui tampilan? Pengguna bisa men-klik tombol Refresh atau menekan tombol F5!!   Bayangkan jika pengguna harus memantau halaman ini terus menerus selama jam kerja (misalnya seorang kasir), maka tombol F5 bisa jadi tombol yang paling cepat pudar di keyboard 😉

Lalu apakah ada solusi untuk membuat halaman ini terlihat lebih profesional dimana perubahan data oleh user lain bisa langsung diperbaharui?  Yup!  Saya bisa menggunakan apa yang disebut sebagai teknik Reverse Ajax.   Bila biasanya client yang duluan menghubungi server, maka pada Reverse Ajax, seolah-olah server yang akan menghubungi client.   Solusi lain adalah dengan memakai WebSocket (bagian dari HTML5) dengan syarat browser pengguna sudah mendukung.

Teknik Reverse Ajax terdiri atas polling, piggyback, dan Comet (long polling).

Polling adalah cara yang paling sederhana, yaitu dengan membuat sebuah timer JavaScript yang memeriksa perubahan data di server secara periodik. Cara ini akan sangat membebani server karena selalu ada data yang dikirim dari server biarpun tidak ada perubahan.

Piggyback akan mengembalikan status perubahan bersamaan dengan sebuah request normal. Misalnya, pada saat user men-klik sesuatu di halaman, sekalian ikut kembalian event perubahan.   Cara ini lebih hemat bandwidth dibandingkan dengan teknik polling. Kelemahannya adalah harus ada sebuah request yang normal terlebih dahulu, baru event perubahan yang terakumulasi di server dikirim balik bersamaan dengan reponse.   Saya tidak bisa menggunakan piggyback karena saya ingin halaman tetap diperbaharui biarpun pengguna hanya duduk diam menatap monitor.

Teknik Reverse Ajax yang lebih efisien adalah Comet atau sering disebut juga dengan long polling. Pada Comet, client akan melakukan request, tetapi server tidak akan langsung mengembalikan nilai.   Request ini akan terbuka untuk waktu yang lama.   Selama selang waktu tersebut, server dapat mengirim data ke client kapan saja.   Teknik ini adalah teknik yang paling efisien karena bandwidth hanya akan dipakai bila server perlu mengembalikan data ke client.

Saya akan memakai teknik Comet.   Untuk itu, saya harus memenuhi persyaratan, yaitu memiliki server yang mendukung asynchronous reponse.  Selain itu saya juga perlu memakai bahasa pemograman yang mendukung multithreading. Sebagai contoh, bila saya memakai Apache + PHP ‘murni’ dan berusaha menghentikan request dengan sleep(), maka selama thread di-sleep(), seluruh client lain tidak akan bisa mengakses web!!   Kinerja web malah akan jauh lebih buruk dibanding memakai teknik polling.  Server apa yang sudah mendukung asynchronous response?   Tomcat 6 ke atas, Jetty 6 ke atas, Glassfish dengan Grizzly, dan sebagainya.   Saya akan memakai Tomcat 7.

Apa contoh teknologi bahasa pemograman yang mendukung asynchronous response?   Servlet 3 di Java EE!   Ada juga framework yang mempermudah seperti CometD, DWR (Direct Web Remoting), dan Atmosphere.   Selain itu,  Spring Web MVC sejak versi 3.2 telah mendukung asynchronous response.   Karnea aplikasi saya dari awal dikembangkan dengan Spring Web MVC, maka yang perlu saya lakukan adalah men-upgrade versi Spring yang dipakai ke versi 3.2.   Dengan memakai Apache Maven, yang perlu saya lakukan hanya mengganti nilai property org.springframework-version menjadi 3.2.0.RELEASE, dan Maven akan mendownload JAR yang dibutuhkan.

Setelah men-upgrade versi Spring ke 3.2.0.RELEASE, saya perlu mengubah file web.xml. Perubahan yang saya lakukan adalah:

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">

Selain itu, saya perlu menambahkan <async-supported> di definisi org.springframework.web.servlet.DispatcherServlet milik Spring Web MVC seperti yang terlihat berikut ini:

<servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>    
    <init-param>      
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
    </init-param>    
    <load-on-startup>1</load-on-startup>
    <async-supported>true</async-supported>
</servlet>

Karena saya memakai Spring Security yang mendefinisikan sebuah filter di web.xml yaitu org.springframework.web.filter.DelegatingFilterProxy, maka saya juga perlu menambahkan <async-supported> pada definisi filter tersebut. Berikut ini adalah perubahan yang saya lakukan:

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <async-supported>true</async-supported>    
  </filter>
  <filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>ASYNC</dispatcher>
  </filter-mapping>
</filter>

Setelah ini, saya bisa mulai membuat kode program.  Saya akan mulai dari service layer.  Saya sedikit frustasi karena tidak menemukan pendekatan yang lebih rapi yang tidak mengotori service layer dengan objek DeferredResult milik presentation layer.  Saya selalu berusaha menghindari coupling seperti ini, tapi sepertinya tidak ada pilihan yang lebih gampang.   Pada service layer, saya mendefisinikan sebuah  struktur untuk menampung DeferredResult yang mewakili asynchronous request seperti berikut ini:

private List<DeferredResult<Boolean>> listDeferredResult = new Vector<DeferredResult<Boolean>>();

Saya memakai Vector karena class tersebut thread safe.  Pada asynchronous request yang diberikan halaman kasir, saya hanya mengembalikan sebuah nilai true bila halaman perlu diperbaharui atau false bila tidak.  Hal ini karena tabel dibuat dengan jqGrid dan saya tidak ingin repot mengelola data.

Pada satu atau lebih service yang menyebabkan perubahan di halaman kasir, saya memberikan kode program seperti berikut ini:

public Pemesanan prosesTambahPemesanan(Pemesanan pemesanan) {
   ...
   prosesNotifikasiPembayaran();
}

public Pemesanan prosesUpdatePemesanan(Pemesanan pemesanan) {
   ...
   prosesNotifikasiPembayaran();
}

private void prosesNotifikasiPembayaran() {
   for (DeferredResult<Boolean> deferredResult: listDeferredResult) {
      deferredResult.setResult(Boolean.TRUE);
   }
}

Method prosesNotifikasiPembayaran() akan menyebabkan asynchronous response selesai dengan nilai kembali berupa true.

Tidak lupa saya juga menyediakan method untuk mendaftar dan menghapus setiap DeferredResult yang ada di Vector, seperti berikut ini:

public void daftarNotifikasiPembayaran(DeferredResult<Boolean> deferredResult) {
  listDeferredResult.add(deferredResult);
}

public void hapusNotifikasiPembayaran(DeferredResult<Boolean> deferredResult) {
  listDeferredResult.remove(deferredResult);
}

Ok, service layer sudah selesai, sekarang saya akan ke presentation layer.  Saya menambahkan method berikut ini di controller:

@RequestMapping(value="pembaharuan")
@ResponseBody
public DeferredResult<Boolean> notifikasiPembayaran() {
  final DeferredResult<Boolean> deferredResult = new DeferredResult<Boolean>(30000l, Boolean.FALSE);
  pemesananService.daftarNotifikasiPembayaran(deferredResult);
  deferredResult.onCompletion(new Runnable() {
    @Override
    public void run() {
      pemesananService.hapusNotifikasiPembayaran(deferredResult);
    }
  });
  return deferredResult;
}

Pada kode program controller tersebut, saya memberikan waktu tunggu 30.000 ms atau 30 detik.  Bila setelah 30 detik, belum ada yang memanggil method DeferredResult.setResult(), maka nilai false akan dikembalikan.

Langkah terakhir, menambahkan kode program ini di view JSP:

...
<spring:url value="/pembayaran/pembaharuan" var="urlPembaharuan" />
...
function comet() {
  $.getJSON("${urlPembaharuan}", function(data) {
     if (data==true) {
        gridUtama.trigger('reloadGrid');
     }
     comet();
  });
}
...

Pada kode program di atas, bila hasil asynchronous request adalah true, maka dialog jqGrid akan di-refresh.   Setelah itu, tidak peduli nilai kembali adalah true atau false, fungsi tersebut akan kembali memanggil dirinya sendiri.

Untuk mencobanya, saya membuka tiga browser yang berbeda, dimana pada 2 browser, saya membuka halaman untuk kasir.  Satu browser-nya lagi untuk perubahan yang harus di-update oleh halaman kasir, seperti pada gambar berikut ini:

Pengujian

Pengujian

Pada gambar di atas, pada saat tombol “Iya” di-klik, maka tabel di browser Kasir A maupun browser Kasir B akan di-reload secara otomatis.

Teknik Comet (long polling) memang agak mirip polling, dimana client harus melakukan request secara periodik.  Tetapi penggunaan asynchronous request membuat Comet jauh lebih efisien dibanding polling:

  1. Pada  polling,  bila interval adalah 30 detik, maka client benar-benar harus menunggu selama 30 detik baru ada hasil yang diperoleh.  Pada Comet, bila interval adalah 30 detik, lalu pada detik ke-15 sudah ada event, maka hasil akan segera dikembalikan pada saat itu juga.
  2. Karena alasan di atas, untuk memperoleh hasil yang real-time, maka polling biasanya memiliki interval yang singkat, misalnya 10ms.   Hal ini menyebabkan semakin banyak request yang dilakukan ke server secara periodik dan akan membebani server.
Iklan

Tomcat Native Library: Bagaimanapun Asli Tetap Lebih Cepat

Sebagai seorang programmer yang mencintai kebebasan, dari awal saya tidak berharap terlalu banyak pada Java. Program yang dibuat dengan Java berjalan pada lapisan virtual, sehingga saya tidak dapat memprogram mesin komputer secara leluasa. Maklum, lapisan virtual ini dirancang untuk tetap sama diberbagai platform yang berbeda. Pertanyaannya adalah, jika ingin menyamakan semua platform, lalu bagaimana dengan kelebihan masing-masing platform yang tidak dimiliki platform lainnya? Itu sebabnya sebagai programmer di platform Windows, saya masih menghabiskan waktu bersama Visual C++. Sementara Java cukup mempan dipakai untuk mencari duit (baca: bekerja). Java memungkinkan programmer bekerja dengan cepat dan meningkatkan learning curve; sesuatu yang sangat dibutuhkan oleh industri software.

Kembali ke laptop: Untuk meningkatkan kinerja Apache Tomcat pada production, saya dapat memanfaatkan Tomcat Native Library. Untuk versi Windows, Tomcat Native Library tersedia dalam bentuk file dll (dynamic linking library), dengan nama tcnative-1.dll jika mendownload versi binary-nya. O ya, Tomcat Native Library menggunakan Apache Portable Runtime (APR). Ini adalah static library yang berisi sekumpulan API untuk hal-hal yang platform-dependent (spesifik pada platform tertentu). Source APR terdapat dalam bentuk C/C++, tersedia untuk platform Windows, Linux/Unix, OS2, Netware, dsb. Pada distribusi Windows, source tersebut dapat di-build dengan menggunakan Visual C++. Aku perlu mendownload APR hanya jika aku men-build Tomcat Native Library dari source. Jika aku men-download versi binary, satu-satunya yang aku butuhkan hanya file tcnative-1.dll.

Pada saat menjalankan Tomcat tanpa native library, aku akan mendapatkan salah satu baris berikut di output logger/console-nya:

INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments
was not found on the java.library.path: ...

Untuk mengaktifkan native library, aku hanya perlu meletakkan lokasi folder yang mengandung tcnative-1.dll ke dalam environment variable PATH. Atau, jika aku memakai Eclipse misalnya, aku dapat men-set property java.library.path. Pada perspektif Java EE di Eclipse, aku dapat men-double click nama server, lalu men-klik Open Launch Configuration pada halaman Overview yang muncul. Lalu aku muncul kotak dialog Edit Configuration. Disini aku memilih tab Arguments, lalu pada bagian VM Arguments, aku menambahkan baris seperti berikut ini:

-Djava.library.path="C:\lokasi_folder_dll_native"

Sekarang, jika aku menjalankan server Apache Tomcat, aku akan mendapatkan baris seperti ini:

INFO: Loaded APR based Apache Tomcat Native library 1.1.16.

Apache Tomcat: Konfigurasi JNDI

Tomcat juga mendukung JNDI layaknya application server JEE lainnya, hanya saja konfigurasinya lebih tidak user-friendly. Kali ini aku akan mencoba membuat JNDI Resource yang berupa JDBC Data Sources sehingga aku dapat meng-akses database di kode program melalui nama JNDI. Keuntungannya, jika aku mengganti database, aku hanya perlu merubah konfigurasi JNDI Resource tanpa harus mengubah kode program sedikitpun.

Karena aku memakai Oracle Database 10g, aku men-copy file %ORACLE_HOME%\jdbc\lib\ojdbc14.jar (driver JDBC) ke lokasi %CATALINA_HOME%\lib (lokasi yang berisi library yang berlaku untuk seluruh aplikasi web). Lalu aku menambahkan baris berikut pada web.xml milik aplikasi web:

<resource-ref>
	<res-ref-name>jdbc/databaseDevelopment</res-ref-name>
	<res-type>javax.sql.DataSource</res-type>
	<res-auth>Container</res-auth>
</resource-ref>

Lalu, aku menambahkan baris berikut pada %CATALINA_HOME%\conf\context.xml:

 <Resource name="jdbc/databaseDevelopment"
 	auth="Container"
 	type="javax.sql.DataSource"
 	username="scott"
 	password="tiger"
 	driverClassName="oracle.jdbc.OracleDriver"
 	url="jdbc:oracle:oci:@latihan"
 	maxActive="1"
 	maxIdle="10"
 />

Pada konfigurasi di atas, aku memakai data source standard dari Tomcat yang berdasarkan pada DBCP connection pool (salah satu bagian dari Apache Common project). Setelah itu, aku dapat memulai kode di servlet, misalnya:

Context initialContext = new InitialContext();
Context envContext = (Context) initialContext.lookup("java:comp/env");
DataSource ds = (DataSource) envContext.lookup("jdbc/databaseDevelopment");

cn = ds.getConnection();
Statement st = cn.createStatement();
ResultSet rs = st.executeQuery("SELECT ENAME FROM EMP");
while (rs.next()) {
	output.print(rs.getString(1) + "<br>");
}

Jika tidak ingin mengatur konfigurasi JNDI dengan cara manual, melainkan dengan interface berbasis web layaknya application server lain, aku dapat menggunakan AMS dari SpringSource tc Server.  Tentu saja kenyamanan ini diperoleh dengan biaya tertentu (tidak lagi gratis).

Sekedar Info: SpringSource tc Server

Menurut hasil survei, Spring cointainer merupakan 70% penyebab Tomcat banyak dipakai. Oleh sebab itu, tidak heran jika SpringSource memiliki produk SpringSource tc Server yang merupakan versi enterprise dari Apache Tomcat.

Spring tc Server mendukung semua fitur yang dimiliki oleh Apache Tomcat, serta menambahkan beberapa fitur baru. Salah satu fitur yang ditambahkan adalah dukungan AMS (Application Management Suite). Dengan adanya AMS, administrator bisa mengatur dan memonitor aplikasi web melalui dashboard grafis berbasis web ataupun command-line. Beberapa hal yang bisa dimonitor misalnya: application deadlock, garbage collection metric, dan SQL query time. tc Server juga dilengkapi dengan high concurrency JDBC connection pool, yang disebut tc Server Datasource. Default DBCP datasource masih ada, hanya saja karena bersifat single-threaded, ia tidak sesuai dengan aplikasi yang sering melayani banyak permintaan dalam waktu bersamaan.

tc Server mendukung clustering untuk high-availability melalui session replication dan context-attribute replication. Dengan session replication, setiap object session akan direplikasi ke seluruh anggota cluster, dan di-update jika mengalami perubahan. Jika salah satu server mengalami masalah, maka server lain dapat langsung mengambil alih session secara otomatis. Begitu dengan context-attribute replication, dimana yang di-replikasi adalah web application context.

Fitur lain yang ditawarkan adalah update perbaikan bug secara langsung, tanpa harus menunggu rilis versi baru dari Apache Tomcat. Hal ini karena lebih dari 80% commit source code Apache Tomcat selama dua tahun terakhir dilakukan oleh karyawan SpringSource. Mereka siap mendukung pengguna yang membeli SpringSource tc Server.

Ant Task: Mempermudah Penggunaan Tomcat Manager

Tulisan kali ini masih berhubungan dengan sebelumnya. Aku sudah mencoba menggunakan
Tomcat Manager dengan cara mengakses langsung melalui URL-nya. Kali ini, aku akan menggunakan cara yang
lebih praktis, yaitu melakukan reloading melalui Ant.

Pada paket standar-nya, Ant menyediakan cukup banyak task, mulai dari yang umum dipakai hingga yang unik seperti
JspC untuk men-compile JSP (agar saat dipakai nanti, tidak perlu compile lagi) dan Telnet untuk membuka session
telnet. Bila task-task yang ada dirasa belum cukup, programmer boleh membuat sendiri task baru. Sebagai contoh,
Tomcat menyediakan task tambahan sehingga proses reloading dapat dilakukan melalui Ant.

Aku akan mencoba latihan membuat task baru di Ant. Misalnya, sebuah task sederhana yang akan menampilkan kotak
dialog ke user. Aku mulai dengan membuat class berikut:

import javax.swing.JOptionPane;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;

public class Latihan extends Task {

	private String pesan;
	
	public void setPesan(String pesan) {
		this.pesan = pesan;
	}
	
	public void execute() throws BuildException {
		JOptionPane.showMessageDialog(null, pesan);
	}
}

Setiap task harus merupakan turunan dari class Task atau sejenisnya. Fungsi setPesan
akan dipanggil oleh Ant saat mem-proses atribut dengan nama pesan. Kode utama untuk Task terletak
di execute().

Langkah berikutnya, aku men-jar class tersebut kemudian meletakkan di folder %ANT_HOME%\lib, dimana
%ANT_HOME% adalah lokasi yang berisi instalasi Ant.

Berikutnya, aku bisa menguji task buatanku dengan membuat build.xml yang isinya sebagai berikut:

<?xml version="1.0" ?>

<project name="Latihan" default="main">
  
  <taskdef name="latihanTask" classname="Latihan" />

  <target name="main">
     <latihanTask pesan="Hi, apa kabar?" />
  </target>

</project>

Aku menggunakan taskdef untuk mendefinisikan task baru. Saat dijalankan, Ant akan memunculkan
kotak dialog yang berisi tulisan “Hi, apa kabar?” dan sebuah tombol “OK”.

Sekarang, kembali ke topik, Tomcat menyediakan file catalina-ant.jar di folder lib yang
berisi tambahan task untuk Ant. Beberapa task dalam catalina-ant.jar yang berhubungan dengan Tomcat
Manager antara lain:

org.apache.catalina.ant.DeployTask
org.apache.catalina.ant.ListTask
org.apache.catalina.ant.ReloadTask
org.apache.catalina.ant.ResourcesTask
org.apache.catalina.ant.RolesTask
org.apache.catalina.ant.StartTask
org.apache.catalina.ant.StopTask
org.apache.catalina.ant.UndeployTask

Berikut ini adalah contoh build.xml yang memanfaatkan task tambahan dari Tomcat:

<property name="url" value="http://localhost:8080/manager"/>
<property name="username" value="snake"/>
<property name="password" value="solidsnake"/>

<property name="task" value="/LatihanApacheTomcat-0.1" />
...
<taskdef name="deploy"    classname="org.apache.catalina.ant.DeployTask"/>
<taskdef name="reload"    classname="org.apache.catalina.ant.ReloadTask"/>
<taskdef name="undeploy"  classname="org.apache.catalina.ant.UndeployTask"/>
...
<target name="deploy" description="Install web application"
        depends="compile">
  <deploy url="${url}" username="${username}" password="${password}"
          path="${path}" localWar="file:\${build.home}" />
</target>

<target name="reload" description="Reload web application"
        depends="compile">
  <reload  url="${url}" username="${username}" password="${password}"
          path="${path}"/>
</target>

<target name="undeploy" description="Remove web application">
  <undeploy url="${url}" username="${username}" password="${password}"
          path="${path}"/>
</target>

Pada build.xml di atas, target deploy akan men-deploy aplikasi web yang berada dalam struktur
exploded directory. Aku meletakkan hasil kompilasi langsung ke lokasi CATALINA_HOME/webapps, sehingga
setiap kali ada class yang aku ubah, aku tidak perlu me-restart server, hanya perlu menjalankan target
reload saja. Task tambahan tersebut pada dasarnya juga akan mengakses URL Tomcat Manager, melalui HttpURLConnection
(dapat dilihat dari source code-nya, jika men-download source Tomcat).

Karena aku menggunakan Eclipse, sebelum aku bisa menjalankan task tambahan, aku harus menambahkan catalina-ant.jar
pada classpath Ant milik Eclipse. Caranya adalah dengan membuka menu Window, Preferences, lalu
memilih Ant, Editor, Runtime. Pada tab Classpath, aku dapat menambahkan jar
tersebut.

Apache Tomcat 6: Tidak Mau Sering Restart Server?

Salah satu kendala yang sering ditemui dalam kehidupan sehari-hari saat mengembangkan aplikasi JEE adalah
harus sering restart server untuk melihat hasil perubahan di kode program. Pada aplikasi yang besar,
proses undeploy dan deploy mungkin bisa memakan waktu hingga beberapa menit, belum lagi ditambah waktu
restart server. Bagi yang tidak sabaran,
Tomcat 6 menyediakan Manager yang memungkinkan untuk deploy, undeploy, dan reloading aplikasi web
tanpa harus men-shutdown dan me-restart Tomcat. O ya, karena Tomcat hanya mendukung JSP dan Servlet, sementara
perubahan pada JSP dapat langsung terlihat, fitur ini berguna saat melakukan modifikasi terhadap source
Java seperti servlet. Selain itu, Tomcat juga sudah cukup pintar untuk melakukan reloading secara otomatis pada
kasus-kasus tertentu, misalnya jika file web.xml atau file WAR berubah.

Sebelum memulai memakai Manager, aku harus membuat user terlebih dahulu. Secara default, Tomcat akan
mencari informasi user di file CATALINA_HOME/conf/tomcat-users.xml. Saat aku membuka file ini,
isinya masih kosong. Jadi, aku segera menambahkan baris berikut:

<user name="snake" password="solidsnake" roles="manager" />

Setelah melakukan restart server Tomcat, aku dapat melihat status aplikasi dengan link default sebagai berikut:

http://localhost:8080/manager/html

Browser akan meminta username dan password sebelum dapat melihat informasi aplikasi web yang ada. Dari sini,
aku juga me-reload aplikasi yang ada dengan men-klik link yang tersedia. Tentu saja untuk penggunaan sehari-hari,
akan sangat tidak menyenangkan jika harus membuka halaman ini dan men-klik “reload” setiap kali ada perubahan
class Java di folder “classes” dan libary di folder “lib”.

Cara lain yang paling gampang dan otomatis untuk men-reload aplikasi web adalah dengan memberikan URL tertentu di
browser. Sebagai contoh, untuk mendeploy sebuah aplikasi (dan undeploy terlebih dahulu bila sudah di-deploy sebelumnya),
aku dapat memberikan URL berikut di browser:

http://localhost:8080/manager/deploy?path=/LatihanApacheTomcat&
war=file:C:/LatihanApacheTomcat.war&
update=true

Parameter path menunjukkan context path untuk aplikasi yang akan di-reload; parameter war
berisi lokasi file WAR terbaru (file ini harus berada di host yang sama dengan server Tomcat) atau bisa juga
path yang merujuk ke exploded directory untuk aplikasi web;
dan parameter update bernilai true yang berarti aku ingin melakukan undeploy jika aplikasi sudah
di-deploy sebelumnya. Jika proses berlangsung dengan sukses, aku akan mendapatkan respon berikut:

OK - Undeployed application at
  context path /LatihanApacheTomcat
OK - Deployed application at
  context path /LatihanApacheTomcat

Jika tidak menggunakan WAR melainkan exploded directory, maka aku dapat melakukan reloading dengan
menggunakan URL seperti berikut:

http://localhost:8080/manager/reload?path=/LatihanApacheTomcat

Apache Tomcat 6: Beginners Guide

Aku baru saja menginstall Apache Tomcat 6. Aplikasi berlogo kucing ini termasuk cointaner Java EE yang unik, karena ia tidak mendukung
seluruh spesifikasi Java EE. Tidak seperti JBoss yang dapat menjalankan EJB 3.0, Tomcat 6.0 hanya dapat menjalankan JSP dan Servlet. Lalu
kenapa harus ada Tomcat? Di zaman dahulu kala saat EJB masih rumit, membuat aplikasi JEE sesuai spesifikasi menjadi terlalu bertele-tele.
Tidak semua aplikasi web butuh kekuatan EJB. Sebagai contoh, misalnya bagian EJB 3.0 bisa diganti dengan Spring Framework. Dengan
Spring AOP dan Spring IoC, misalnya, programmer bisa mendapatkan fitur deklarative transaction seperti di EJB tetapi dengan
konfigurasi yang lebih gampang. Btw, Spring adalah framework yang sangat luas dan mencakup banyak hal. Spring tidak harus selalu dikaitkan
dengan aplikasi web. Aku pernah membuat aplikasi dekstop (non-web) dengan Spring karena aku ingin memanfaatkan AOP container dan IoC-nya.
Tentu saja ada beberapa bagian dari framework Spring yang dikhususkan untuk aplikasi web, seperti Spring MVC.

Jika aku meng-ekstrak file program Tomcat di “c:program files”, maka “C:Program Filesapache-tomcat-6.0.18” disebut CATALINA_HOME.
Disini terdapat folder bernama bin yang didalamnya terdapat startup.bat. Seperti yang tercantum dinamanya,
batch file tersebut dipakai untuk menjalankan server Tomcat. Aplikasi web yang hendak aku buat nantinya akan diletakkan di folder bernama

webapps. Sebagai contoh, misalnya, aku membuat folder baru di dalam webapps dengan nama latihanPertama dan menambah beberapa
file ke dalamnya, sehingga struktur folder menjadi:

 CATALINA_HOME
 |
 |-- webapps
     |
     |-- latihanPertama
         |
         |-- index.html
         |-- latA.jsp
         |-- latB.jsp
         |-- latC.jsp

Secara default, aku dapat langsung mengakses aplikasi latihanPertama di browser melalui URL: http://localhost:8080/latihanPertama.
Tetapi perlu di-ingat bahwa aplikasi latihanPertama tidak harus selalu memiliki context path latihanPertama.
Misalnya, jika aku memberikan
context path aplikasiWebPertama pada latihanPertama, maka untuk meng-akses-nya di browser, aku harus menggunakan URL ini:

http://localhost:8080/aplikasiWebPertama.

Bagaimana kalau aku ingin membuat beberapa class Servlet untuk aplikasi latihanPertama? Aku akan membuat folder WEB-INF dan
membuat beberapa file sehingga struktur folder menjadi:

 CATALINA_HOME
 |
 |-- webapps
     |
     |-- latihanPertama
         |
         |-- index.html
         |-- latA.jsp
         |-- latB.jsp
         |-- latC.jsp
         |-- WEB-INF
             |
             |-- test.jsp
             |-- test.html
             |-- web.xml
             |-- classes
             |   |
             |   |-- test.class
             |
             |-- lib
                 |
                 |-- test.jar

Folder WEB-INF ini adalah folder yang spesial, tidak seperti folder lainnya. Misalnya, semua file yang ada di dalam folder ini
tidak dapat di-akses secara langsung oleh user. Saat aku mencoba membuka alamat ini http://localhost:8080/latihanPertama/WEB-INF/test.html,
browser akan protes karena tidak menemukan apa yang aku inginkan. Bagus bukan? Aku dapat meletakkan source code servlet Java, aku juga
dapat meletakkan hasil compile source code tersebut di folder classes, dan meletakkan library apa saja yang aku butuhkan untuk
aplikasi web ini di folder lib, tanpa khawatir dilihat user.

Ada sebuah file unik di folder WEB-INF, yaitu web.xml. File ini berisi konfigurasi aplikasi dan disebut web application
deployment descriptor. O ya, struktur folder WEB-INF dan web.xml tidak ditentukan oleh Tomcat loh, melainkan oleh para perancang
Java Enterprise Edition (Sun). Oleh sebab itu, semua aplikasi web JEE akan memiliki folder WEB-INF tidak peduli dia di-install di Tomcat,
JBoss, WebLogic, ataupun Oracle Application Server (OAS).

Apa yang aku lakukan barusan, dengan membuat folder dan membuat file di dalam folder, sering disebut exploded web application.
Cara lainnya, aku dapat men-zip (istilah Java-nya jar) direktori latihanPertama beserta seluruh isi dan subdirektori-nya
ke dalam file bernama latihanPertama.war.
Ekstensi WAR menunjukkan kalau ini adalah Web Application Archive. Lalu, aku meletakkannya ke folder webapps sehingga struktur
foldernya menjadi:

CATALINA_HOME
 |
 |-- webapps
     |
     |-- latihanPertama.war

Terlihat lebih rapi bukan? Aplikasi tetap dapat di-akses seperti biasa, tetapi kini hanya 1 file zip saja. Tentu saja, dalam proses pengembangan
aplikasi, programmer lebih suka memakai exploded directory. Ngapain harus report-report men-jar dan membuat file WAR? Btw, exploded directory
ini adalah fitur dari Tomcat (dan juga dari kebanyakan application server). Spesifikasi JEE secara resmi hanya mensyaratkan dapat menjalankan
file WAR saja dan tidak mensyaratkan application server untuk dapat menjalankan struktur exploded directory.