Kamis, 25 November 2010

Simple Demo Jsp Servlet

Kita akan belajar membuat sebuah aplikasi web MVC mengunakan teknologi JSP dan Servlet. Kita akan mengunakan Eclipse (Download) sebagai Java Editor dan Tomcat 6 Download sebagai Web Container.

Aplikasi ini akan menunjukkan betapa mudahnya membuat sebuah aplikasi MVC menggunakan JSP dan Servlet. Aplikasi ini hanya memiliki fungsi login sebagai contoh.

Kita akan mengupas lebih dalam Konsep MVC seiring dengan proses pembuatan.


Baiklah mari segera kita mulai...

Langkah #1 : Membuat sebuah Dynamic Web Project. Buka Eclipse. Klik File -> New -> Other -> Web -> Dynamic Web Project.
 
Berikan nama Project "Simple Login". Klik Finish.

Langkah #2 : Buat halaman LoginEntry.jsp
Klik kanan pada project Pilih New -> JSP. Berikan nama LoginEntry.jsp


<html>
<head>
    <title>SimpleLoginDemo</title>
</head>
<body>
    <form action="LoginServlet" method="post">
        Masukan Nama dan Password<br/>
        Nama  <input type="text" name="txtName" /><br/>
        Password <input type="password" name="txtPassword"/><br/>
        <input type="submit" value="submit"/>  
    </form>
</body>
</html>

Langkah #3 : Buat halaman Sukses.jsp
<html>
<head>
<title>Login Berhasil</title>
</head>
<body>
    <H1>Login Berhasil</H1>
    Name Login : <%= request.getAttribute("name") %> <br/>
    Password Login : <%= request.getAttribute("password") %> <br/>
    Waktu Login : <%= request.getAttribute("logintime") %>    
</body>
</html>

Langkah #4 : Buat halaman Error.jsp
<html>
<head>
<title>Error</title>
</head>
<body>
    <H1>Login Gagal</H1>
    <a href="LoginEntry.jsp">Login Ulang</a>
</body>
</html>

Langkah #5 : Buat Servlet Berikan Nama : LoginServlet
 

 Tambahkan baris kode berikut pada LoginServlet.java yang baru saja dibuat.
package greenhornsjava.controller;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.sun.org.apache.bcel.internal.generic.NEW;

public class LoginServlet extends HttpServlet {
 private static final long serialVersionUID = 1L;
       
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  doPost(request, response);
 }

 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  String name = request.getParameter("txtName");
  String password = request.getParameter("txtPassword");
  
  if(!name.equals("admin") && !password.equals("admin")) {
   request.getRequestDispatcher("Error.jsp").forward(request, response);
  } else {
   SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
   String now = sdf.format(new Date(System.currentTimeMillis()));
   
   request.setAttribute("name", name);
   request.setAttribute("password", password);
   request.setAttribute("logintime", now);
   request.getRequestDispatcher("Sukses.jsp").forward(request, response);
  }
 }
}

Langkah #6 : Cek File yang berada di Folder WebContent -> WEB-INF -> web.xml
<?xml version="1.0" encoding="UTF-8"?>
<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_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <servlet>
    <servlet-name>LoginServlet</servlet-name>
    <servlet-class>greenhornsjava.controller.LoginServlet</servlet-class>
  </servlet>
  
  <servlet-mapping>
    <servlet-name>LoginServlet</servlet-name>
    <url-pattern>/LoginServlet</url-pattern>
  </servlet-mapping>
</web-app>

Langkah #7 : Export File menjadi WAR dan deploy di Web Server Anda...
Silahkan mencoba...

Selasa, 23 November 2010

Spring : How to Declarative Transaction

Dalam tulisan ini kita akan mengekspose Spring declarative transaction dengan menggunakan fitur anotation (hanya support di java 1.5 dan seterusnya...)
dan penggunaan SimpleJdbcInsert.


Berikut contoh penggunaan :

BookManagerImpl merupakan class yang mengatur proses DML pada table 'book' pada database 'spring_book'. Object BookManagerImpl akan dibungkus dengan Transaction pada mode 'read-only' secara default. Method insertBooks(List books) akan dioverride dengan mode transaction yang berbeda sehingga setiap kali method ini dipanggil maka akan dibungkus dengan sebuah transaksi yang baru.


CREATE DATABASE spring_book;

CREATE TABLE `book` ( 
 `id`   varchar(10) NOT NULL,
 `name` varchar(50) NOT NULL,
 PRIMARY KEY(`id`)
);
package greenhornsjava.spring.entity;

public class Book {
 private String id;
 private String name;
 
 public Book(String id, String name) {
  this.id = id;
  this.name = name;
 }
 
 public String getId() {
  return id;
 }
 public void setId(String id) {
  this.id = id;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 } 
}


package greenhornsjava.spring.trx;

import java.util.List;

public interface BookManager {
 public void insertBooks(List books);
}
package greenhornsjava.spring.trx;

import greenhornsjava.spring.entity.Book;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 * BookManagerImpl adalah contoh class yang mengimplementasikan
 * Kemampuan Spring dalam mengatur transaksi secara declarative.
 */
@Transactional(readOnly = true)
public class BookManagerImpl implements BookManager {
 // SimpleJdbcInsert adalah Object JDBC Template yang disediakan oleh Spring Framework 
 private SimpleJdbcInsert insertBook;
 
 public BookManagerImpl(DataSource dataSource) {
  insertBook = new SimpleJdbcInsert(dataSource).withTableName("book");
 }
 
 /**
  * Secara declarative menjadikan method ini 'terbungkus' oleh transaksi baru. 
  * Sehingga jika terjadi Exception maka keseluruhan proses insert pada method ini
  * akan di-rollback.
  */
 @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
 public void insertBooks(List books) {
  for(Object o : books) {
   Book b = (Book) o;
   Map parameters = new HashMap();
   parameters.put("id", b.getId());
   parameters.put("Name", b.getName());
   insertBook.execute(parameters);
  }
 }
 
 public static void main(String[] args) {  
  AbstractApplicationContext context = new FileSystemXmlApplicationContext(
    new String[] { "DataAccessContext.xml" });

  context.registerShutdownHook();

  final BeanFactory bf = (BeanFactory) context;
  BookManager bookManager = (BookManager) bf.getBean("bookManager");
  
  Book b1 = new Book("book1", "Harry Potter");
  Book b2 = new Book("book2", "The Lost Symbol");
  Book b3 = new Book("book3", "The Adv of Donald Duck");
  
  List books = new ArrayList();
  books.add(b1);
  books.add(b2);
  books.add(b3);
  
  // Proses Insert Book akan berhasil dan tercatat secara fisik di DB
  bookManager.insertBooks(books);
  
  Book b4 = new Book("Book4", "The Destination");
  
  List books2 = new ArrayList();
  books2.add(b4);
  books2.add(b1);
  
  // Proses Insert Book akan gagal dan Book dengan id:Book4 tidak akan tersimpan
  // karena method telah 'terbungkus' transaksi
  bookManager.insertBooks(books2);
 }
}

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
    
    <bean id="bookManager" class="greenhornsjava.spring.trx.BookManagerImpl">
        <constructor-arg ref="dataSource" />
    </bean>
    
    <!--  Bagian ini akan memberitahukan container agar men-scan semua
          object/method yang ber-anotasi @Transactional agar transaksinya dimanage
          oleh Spring -->
    <tx:annotation-driven transaction-manager="txManager"/>
    
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/spring_book" />
        <property name="username" value="root" />
        <property name="password" value="keriting" />
    </bean>
    
    <bean id="txManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
</beans>

Catatan : Object yang akan menggunakan Spring Declarative Transaction HARUS mengimplement sebuah Interface dimana method2 yang dimaksudkan agar 'dibungkus' dengan transaksi dapat dimanage oleh Spring.

Senin, 22 November 2010

Spring : Depedency Injection Framework

Spring merupakan salah satu DI (Depedency Injection) Framework yang sukses dipakai dalam pembangunan Software berbasis Java.
Spring menjembatani class yang berkaitan erat dengan class dependency-nya melalui konfigurasi sehingga lebih loosely couple / tidak terikat.

Berikut contoh penggunaan Spring sebagai DI framework
Class Car dan Plane merupakan parameter constructor untuk class TransportationTest. Dengan menggunakan file external yang dimanage oleh Spring maka keterikatan class TransportationTest dapat dikonfigurasi di file external(xml).

public abstract class Vehicle { 
 public abstract void move(); 
}

public class Car extends Vehicle{ 
 public void move() {
  System.out.println("Driving fast..");  
 } 
}

public class Plane extends Vehicle{ 
 public void move() {
  System.out.println("Flying fast");  
 }
}

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class TransportationTest {
 private Vehicle vehicle;
 
 public TransportationTest(Vehicle vehicle) {
  this.vehicle = vehicle;
 }
 
 public void testVehicle() {
  vehicle.move();
 }
 
 public static void main(String[] args) {
  /*  
  // dependency injection tanpa spring menyebabkan 
  // class TransportationTest terikat erat dengan class Car
  // pada saat instantiation  
  Car car = new Car();
  TransportationTest test = new TransportationTest(car);
  test.testVehicle();
  
  // dependency injection tanpa spring menyebabkan 
  // class TransportationTest terikat erat dengan class Plane
  // pada saat instantiation  
  Plane plane = new Plane();
  TransportationTest test2 = new TransportationTest(plane);
  test2.testVehicle();  
  */
  
  // load spring context
  AbstractApplicationContext context = new FileSystemXmlApplicationContext(
    new String[] {"ApplicationContext.xml"});
  
  // gunakan method ini utk mematikan spring container 
  // di lingkungan pengembangan desktop 
  context.registerShutdownHook();
  
  final BeanFactory bf = (BeanFactory)context;
  
  // dependency injection versi spring tidak menyebabkan 
  // class TransportationTest terikat erat dengan class yang 
  // menjadi parameter contructornya (Car ataupun Plane).
  // Parameter constructor dikonfigurasi di file yang di-manage oleh Spring
  TransportationTest test1 = (TransportationTest) bf.getBean("transportationTest1");  
  test1.testVehicle(); 
  
  TransportationTest test2 = (TransportationTest) bf.getBean("transportationTest2");  
  test2.testVehicle();
 }
}

file configurasi : ApplicationContext.xml, letakan di direktori yang sama dengan class TransportationTest
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
    
    <bean id="car" class="Car" />
    <bean id="plane" class="Plane" />
    
    <bean id="transportationTest1" class="TransportationTest">
        <constructor-arg ref="car" />
    </bean>
    
    <bean id="transportationTest2" class="TransportationTest">
        <constructor-arg ref="plane" />
    </bean>        
</beans>

Minggu, 21 November 2010

Thread : How to wait() and notify()

Sebuah Thread dapat dihentikan sementara waktu dan memberika kesempatan pada thread yang lain untuk dieksekusi. Thread yang lain dapat men-notify agar thread dengan status 'wait' dapat dijalankan kembali prosesnya.

Berikut contoh penggunaan method wait() dan notify...

Terdapat 3 class masing-masing berfungsi untuk mengenerate Bilangan Ganjil, Genap dan Bulat. Thread Generator Bilangan Genap dan Bulat  akan berhenti jika telah mencapai batas angka tertentu sampai Ketika diakhir proses Generator Bilangan Ganjil akan me-notify Thread Generator Bilangan Bulat dan Genap untuk kembali melanjutkan prosesnya.

public class GeneratorBilanganBulat extends Thread{
 private int maxNumber = 0;
 private double sleepSec = 0;
 private int waitAt ;
 
 public volatile boolean finished = false;
 
 public GeneratorBilanganBulat(int max, double miliSecSleep, int waitAt) {
  maxNumber = max;
  sleepSec = miliSecSleep;
  waitAt = waitAt;
 }

 public void run() {
  try {
   int evenSeq = 1;
   for (int i = 0; i <= maxNumber; i++) {
    System.out.println("BULAT (" + evenSeq++ +") : " + i);
    if(i == waitAt) { 
     synchronized(this) {
      wait();
     }
    }
    sleep((long) (sleepSec*1000));
   }
  } catch (InterruptedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
}
public class GeneratorBilanganGenap extends Thread{
 private int maxNumber = 0;
 private double sleepSec = 0;
 private int waitFor;
 
 public GeneratorBilanganGenap(int max, double miliSecSleep, int waitFor) {
  maxNumber = max;
  sleepSec = miliSecSleep;
  this.waitFor = waitFor;
 }

 public void run() {
  try {
   int seq = 1;
   for (int i = 0; i <= maxNumber; i++) {
    if(i%2 == 0) {
     System.out.println("GENAP (" + seq++ +") : " + i);
     
     if (i == waitFor) {
      synchronized(this) {
       wait();
      }
     }
     // hentikan proses utk jangka waktu tertentu 
     // jika telah menemukan bilangan genap
     sleep((long) (sleepSec*1000));
    }
   }
  } catch (InterruptedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 } 
}

public class GeneratorBilanganGanjil extends Thread{
 private int maxNumber = 0;
 private double sleepSec = 0;
 private GeneratorBilanganGenap genapThread;
 private GeneratorBilanganBulat bulatThread;
 
 public GeneratorBilanganGanjil(int max, double miliSecSleep, 
           GeneratorBilanganGenap genapThread, GeneratorBilanganBulat bulatThread) {
  maxNumber = max;
  sleepSec = miliSecSleep;
  this.genapThread = genapThread;
  this.bulatThread = bulatThread;
 } 
 
 public void run() {
  try {
   int evenSeq = 1;
   for (int i = 0; i <= maxNumber; i++) {
    if(i%2 == 1) System.out.println("GANJIL (" + evenSeq++ +") : " + i);
    
    sleep((long) (sleepSec*1000));
    
   }
  } catch (InterruptedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
    
  synchronized(genapThread ) {
   System.out.println("Ganjil sudah selesai lanjutkan dengan yg Genap");
   genapThread.notify();
  }
  synchronized(bulatThread ) {
   System.out.println("Ganjil sudah selesai lanjutkan dengan yg Bulat");
   bulatThread.notify();
  }
 }
}

public class ThreadTest {
 public static void main(String[] args) throws InterruptedException {
  GeneratorBilanganGenap genapThread = new GeneratorBilanganGenap(30, 0.2, 10);
  GeneratorBilanganBulat bulatThread = new GeneratorBilanganBulat(30, 0.2, 20);
  GeneratorBilanganGanjil ganjilThread = new GeneratorBilanganGanjil(30, 0.2, genapThread, bulatThread);
  genapThread.start(); 
  bulatThread.start();
  ganjilThread.start();  
 }
}
untuk dapat menjalankan fungsi wait dan notify maka bentuk umumnya adalah sbb:
synchronized (someObject) {
    someObject.wait();
}

/* different thread / object */
synchronized (someObject) {
    someObject.notify();
}

Perkenalan Thread

Thread merupakan satuan kecil dari proses dalam pemograman Java. Dengan meng-extends Thread atau meng-implements Runnable maka sebuah Class dapat menjadi sebuah Proses yg bisa dieksekusi secara bersamaan dengan Main Thread (Thread utama yang terdapat pada class yg memiliki public static void Main(...) ketika meluncurkan program pertama kali).
Thread digunakan untuk melakukan instruksi khusus yang waktu eksekusinya dapat berbarengan dengan Main Thread.

Statement yang akan dijalankan oleh oleh sebuah Thread di tempatkan pada method run().

public class GeneratorBilanganGenap extends Thread{
 private int maxNumber = 0;
 private double sleepSec = 0;
 private String name;
 
 public GeneratorBilanganGenap(String name, int max, double miliSecSleep) {
  this.name = name;
  maxNumber = max;
  sleepSec = miliSecSleep;
 }

 public void run() {
  try {
   int seq = 1;
   for (int i = 0; i <= maxNumber; i++) {
    if(i%2 == 0) {
     System.out.println("Name : " + name + ", urutan(" + seq++ +") : " + i);
     
     // hentikan proses utk jangka waktu tertentu 
     // jika telah menemukan bilangan genap
     sleep((long) (sleepSec*1000));
    }
   }
  } catch (InterruptedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
 
 public static void main(String[] args) {
  // create thread masukan parameter constructor 
  GeneratorBilanganGenap generator1 = new GeneratorBilanganGenap("T1", 20, 0.2);
  GeneratorBilanganGenap generator2 = new GeneratorBilanganGenap("T2", 40, 0.2);
  
  // mulai jalankan thread / proses
  generator1.start();
  generator2.start();
 }
}


Dengan meng-create object Thread tidak serta merta akan menjalankan statement pada method Run(). Agar tereksekusi harus menjalankan method start() pada Thread tersebut.

Catatan : method sleep(long miliseconds), berguna untuk menghentikan proses yg dijalankan thread tersebut dalam jangka waktu tertentu dalam hitungan milisecond.