implement project ต้นแบบเสร็จ
เผา slide + present จบ
สิ่งที่ได้จากการทำโปรเจคนี้ เข้าใจ spring มากขึ้น (เกี่ยวไหมเนี่ย 555)
Showing posts with label EJB. Show all posts
Showing posts with label EJB. Show all posts
13.11.08
Seam Hello World
Seam Hello World
เกริ่นนำ
Seam คือ application framework สำหรับ JavaEE5 เป็นโปรเจคหนึ่งของ JBoss พัฒนาขึ้นโดย Gavin King (ผู้เริ่มคิดค้น Hibernate ORM framework) โดย framework พัฒนาขึ้นโดยนำแนวคิดในกาัรพัฒนา web application framework หลายๆ ตัวมาใช้โดยเป้าหมายของ framework ตัวนี้คือ
"One of the (several) goals of Seam is to bring Ruby On Rails style productivity to the Java EE platform" (^^)
ความสามารถพื้นฐานของ seam คือมันเป็นกาวที่ทำให้ EJB3 กับ JSF มันเชื่อมต่อกันได้อย่างสวยงาม ถ้ามองกันการพัฒนา web application ตามมาตรฐานของ Sun ที่มีอยู่อาจต้องใช้ JNDI lookup, ประกาศ JSF backing bean, facade business method หรือความพยายามในการส่ง object ข้ามไปยัง tier ต่างๆ ที่เรารู้จักกันใน pattern ที่ชื่อ DTO (Data Transfer Object) แต่ seam มันบอกว่าสิ่งเหล่านี้เป็นความฟุ่มเฟื่อยแล้วมันจะ integerate JSF กับ EJB3 ให้เองโดยเราไม่ต้องไปเขียน xml config อะไรให้ฟุ้มเฟือย ในตัวอย่างนี้จะมาดูว่ามันเชื่อมต่อกันยังไง (คร่าวสุดๆ นะเพราะอยากให้เห็น code โดยรวมก่อน)
ลงมือ
1. สร้างโปรเจค
ก่อนอื่นติดตั้ง Eclipse + JBoss Tool ให้เรียบร้อย (หรืออาจใช้ seam gen สร้างโปรเจคขึ้นมาแล้วจับยัด (import) ลง Eclipse) เมื่อติดตั้งเรียบร้อยแล้วก็สร้าง seam web project ขึ้นมา config ให้เรียบร้อยเลือก deploy เป็น ear นะ (สมมุติ project นี้ชื่อ hello)
2. สร้าง Data Model
เกริ่นนำ
Seam คือ application framework สำหรับ JavaEE5 เป็นโปรเจคหนึ่งของ JBoss พัฒนาขึ้นโดย Gavin King (ผู้เริ่มคิดค้น Hibernate ORM framework) โดย framework พัฒนาขึ้นโดยนำแนวคิดในกาัรพัฒนา web application framework หลายๆ ตัวมาใช้โดยเป้าหมายของ framework ตัวนี้คือ
"One of the (several) goals of Seam is to bring Ruby On Rails style productivity to the Java EE platform" (^^)
ความสามารถพื้นฐานของ seam คือมันเป็นกาวที่ทำให้ EJB3 กับ JSF มันเชื่อมต่อกันได้อย่างสวยงาม ถ้ามองกันการพัฒนา web application ตามมาตรฐานของ Sun ที่มีอยู่อาจต้องใช้ JNDI lookup, ประกาศ JSF backing bean, facade business method หรือความพยายามในการส่ง object ข้ามไปยัง tier ต่างๆ ที่เรารู้จักกันใน pattern ที่ชื่อ DTO (Data Transfer Object) แต่ seam มันบอกว่าสิ่งเหล่านี้เป็นความฟุ่มเฟื่อยแล้วมันจะ integerate JSF กับ EJB3 ให้เองโดยเราไม่ต้องไปเขียน xml config อะไรให้ฟุ้มเฟือย ในตัวอย่างนี้จะมาดูว่ามันเชื่อมต่อกันยังไง (คร่าวสุดๆ นะเพราะอยากให้เห็น code โดยรวมก่อน)
ลงมือ
1. สร้างโปรเจค
ก่อนอื่นติดตั้ง Eclipse + JBoss Tool ให้เรียบร้อย (หรืออาจใช้ seam gen สร้างโปรเจคขึ้นมาแล้วจับยัด (import) ลง Eclipse) เมื่อติดตั้งเรียบร้อยแล้วก็สร้าง seam web project ขึ้นมา config ให้เรียบร้อยเลือก deploy เป็น ear นะ (สมมุติ project นี้ชื่อ hello)
2. สร้าง Data Model
package org.domain.hello.entity;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.jboss.seam.annotations.Name;
@Entity
@Name("person")
public class Person implements Serializable{
private static final long serialVersionUID = 1L;
private long id;
private String name;
@Id @GeneratedValue
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.jboss.seam.annotations.Name;
@Entity
@Name("person")
public class Person implements Serializable{
private static final long serialVersionUID = 1L;
private long id;
private String name;
@Id @GeneratedValue
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
ด้วยความง่ายของ EJB3 เราสร้าง POJO + Annotation ก็จะกลายเป็น component หนึ่งของ EJB3 ในตัวอย่างนี้เป็น entity bean
โดยเราใช้ @Entity annotation เพื่อจะบอกว่าเราจะ map class นี้กับ relational database table ไหน และ attribute ที่เราอยู่ใน class ก็จะ map เข้ากับ column ใน table นั้น ดังนั้น 1 row ก็จะเท่ากับ 1 person instance (เพราะว่า seam บอกว่าการ configuration เป็นสิ่งทีมันพยายามหลีกเลี่ยงจึงใช้ annotation ในการช่วย config และเราไม่ต้องไปเขียน config xml ให้ฟุ่มเฟือย) และมี @Id เพื่อบอกถึง attribute ที่มันเป็น primary key และใช้ @GeneratedValue เพื่อบอกให้ application server สร้างค่าให้อัตโนมัติกับ Person instance เมื่อ save ลง database (ในตัวอย่างจะเห็นว่าเราไม่ต้องระบุชื่อ column เพราะใน table กับ class เราตั้งชื่อตรงกัน แต่ถ้าคนละชื่อต้องใช้ annotation เพื่อระบุชื่อลงด้วย)
ส่วนสำคัญที่สุดของ class นี้คือ @Name มันเป็นการ register กับ seam เพื่อให้เราสามารถเข้าจัดการ Person bean ตัวนี้ได้โดยการอ้างชื่อ person
3. Map ตัว Data Model กับ Web Formโดยเราใช้ @Entity annotation เพื่อจะบอกว่าเราจะ map class นี้กับ relational database table ไหน และ attribute ที่เราอยู่ใน class ก็จะ map เข้ากับ column ใน table นั้น ดังนั้น 1 row ก็จะเท่ากับ 1 person instance (เพราะว่า seam บอกว่าการ configuration เป็นสิ่งทีมันพยายามหลีกเลี่ยงจึงใช้ annotation ในการช่วย config และเราไม่ต้องไปเขียน config xml ให้ฟุ่มเฟือย) และมี @Id เพื่อบอกถึง attribute ที่มันเป็น primary key และใช้ @GeneratedValue เพื่อบอกให้ application server สร้างค่าให้อัตโนมัติกับ Person instance เมื่อ save ลง database (ในตัวอย่างจะเห็นว่าเราไม่ต้องระบุชื่อ column เพราะใน table กับ class เราตั้งชื่อตรงกัน แต่ถ้าคนละชื่อต้องใช้ annotation เพื่อระบุชื่อลงด้วย)
ส่วนสำคัญที่สุดของ class นี้คือ @Name มันเป็นการ register กับ seam เพื่อให้เราสามารถเข้าจัดการ Person bean ตัวนี้ได้โดยการอ้างชื่อ person
ให้เราสร้างไฟล์ hello.xhtml ไว้ใน WebContent ก่อน
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<head>
<title>Hello Page</title>
</head>
<body>
<h:form>
Please enter your name: <br/>
<h:inputText value="#{person.name}" size="15" /> <br/>
<h:commandButton action="#{manager.sayHello}" value="Say Hello" />
</h:form>
<h:dataTable value="#{fans}" var="fan">
<h:column>
<h:outputText value=#{fan.id}" />
</h:column>
<h:column>
<h:outputText value="#{fan.name}" />
</h:column>
</h:dataTable>
</body>
</html>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<head>
<title>Hello Page</title>
</head>
<body>
<h:form>
Please enter your name: <br/>
<h:inputText value="#{person.name}" size="15" /> <br/>
<h:commandButton action="#{manager.sayHello}" value="Say Hello" />
</h:form>
<h:dataTable value="#{fans}" var="fan">
<h:column>
<h:outputText value=#{fan.id}" />
</h:column>
<h:column>
<h:outputText value="#{fan.name}" />
</h:column>
</h:dataTable>
</body>
</html>
ใน JSF page นี้เราจะใช้ Person bean เป็นตัวเก็บข้อมูลเวลา input field เข้ามาโดยใช้ Expression Language (EL) #{person.name} (สังเกตุเราอ้างถึง person bean และกำหนดว่าให้เก็บลงใน attribute ที่ชื่อ name)
มีการเรียกตัว session bean ชื่อ sayHello ใน manager bean
และส่วนสุดท้ายเป็นการแสดงผลค่า fans ออกมาโดยใช้ dataTable มันจะเป็น iterater แล้ว list รายการ fans ออกมาจาก list ทั้งหมด

เมื่อผู้ใช้คลิกปุ่ม Say Hello ตัว Seam จะสร้าง person bean เพื่อรับ input data และเรียกไปที่ sayHello method ของ class ManagerAction ที่เป็น session bean
มีการเรียกตัว session bean ชื่อ sayHello ใน manager bean
และส่วนสุดท้ายเป็นการแสดงผลค่า fans ออกมาโดยใช้ dataTable มันจะเป็น iterater แล้ว list รายการ fans ออกมาจาก list ทั้งหมด
เมื่อผู้ใช้คลิกปุ่ม Say Hello ตัว Seam จะสร้าง person bean เพื่อรับ input data และเรียกไปที่ sayHello method ของ class ManagerAction ที่เป็น session bean
package org.domain.hello.session;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.domain.hello.entity.Person;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.log.Log;
@Stateless
@Name("manager")
public class ManagerAction implements Manager{
@In @Out
private Person person;
@Out
private List<Person> fans;
@Logger
private Log log;
@PersistenceContext
private EntityManager em;
public String sayHello(){
log.info("start sayHello");
em.persist(person);
fans = em.createQuery("select p from Person p").getResultList();
log.info("end sayHello");
return null;
}
}
manager component ใน Seam คือ ManagerAction ที่เป็น session bean โดยเราใช้ @Name ในการประกาศชื่อ
@In (dependency injection) เป็นการบอกให้ Seam assign ตัว person component เข้ามาให้ โดยมันจะมาจากหน้า JSF form data ซึ่ง Seam จะส่งค่าให้ person ก่อนที่จะเข้ามาทำงานใน method ของ session bean
@Out (dependency outjection) เป็นการบอกให้ Seam assign ค่าของ fans ที่เก็บเป็น list of person หลังจากที่ execution method เสร็จแล้ว เช่นใน sayHello() method เรา update ค่า fans และ person field เมื่อทำงานใน method นี้เสร็จค่า fans จะถูก update ใหม่และส่งให้ที่หน้าเวบเพจ
บางครั้ง Seam อาจเรียกว่า bijection ซึ่งมันเป็นการอ้างถึง injection และ oiutjection ระหว่าง seam component กับ seam managed context
ใน sayHello() method จะทำการเก็บข้อมูลที่กรอบเข้ามาลงใน database ผ่าน EntityManager (JPA) ซึ่งตัว EntityManager ได้มาจากการ inject ผ่าน @PersistenceContext และเมื่อทำงานเสร็จแล้วก็ return null นั่นหมายถึงไม่มีการเปลี่ยนไปหน้า JSF page อื่นต่อ
แน่นอนสุดท้ายตามข้อกำหนด session bean อย่าลืม local ด้วยละ (เมื่อเราต้องการเรียกแบบ local)
package org.domain.hello.session;
import javax.ejb.Local;
@Local
public interface Manager {
public abstract String sayHello();
}
1.11.08
Short Note EJB3
อ่าน EJB in Action แล้วกะจดสรุปไว้นิดหน่อย
เค้าเปรียบการพัฒนาการของ EJB ได้ว่า แมลงสวย --> ช้าง --> วัว (EJB3)
ลักษณะทั่วไป
เมื่อเราสร้าง Java class มันต้องรันผ่าน JVM นี่ก็เหมือนกันใน EJB session bean, mdb ทำงานอยู่บน ejb container ส่วน entity bean ทำงานบน persistence provider (จริงๆ EJB Container ก็คือ JVM แต่เพิ่มความสามารถเข้าไปเช่น transaction management, security management, remoting, webservice)
เค้าเปรียบการพัฒนาการของ EJB ได้ว่า แมลงสวย --> ช้าง --> วัว (EJB3)
ลักษณะทั่วไป
- EJB ให้มองว่ามันเป็น component ที่เราสามารถนำมันมา reuse ได้ เช่นทั้ง 2 app สามารถใช้ component เดียวกันได้ คำว่า component ถ้ามองในเทคโนโลยีอื่นๆ เช่น Microsoft COM+, CORBA
- เราสามารถเขียน EJB โดยที่ไม่ต้องเขียนจัดการกับความซับซ้อนของ error-prone code, transaction, security access control เพราะทาง EJB Container เตรียมความสามารถเหล่านี้ไว้แล้ว เราเพียงแค่ใช้ metadata (Annotation Java5+) ในการประกาศว่าจะใช้ความสามารถเหล่านี้ ดังนั้น code ที่เราเขียนจึงมีไม่มากสามารถพัฒนาได้อย่างรวดเร็ว และเราสนใจเพียงแค่ business logic ไม่ต้องมองถึง infra structure code มากนัก
- Pojo + Annotation = EJB ใน annotation เป็นการเขียน program แบบประกาศว่าเราต้องการ service อะไรให้ EJB เราบ้าง หรือใช้ระบุประเภทของ EJB ก็ได้
- Entity bean ใน EJB3 รองรับ concept OO เช่น Inheritance, Polymophism มันเป็นสิ่งสำคัญมากที่ให้เราสามารถเพิ่ม business logic ใน Entity bean ของเรา ดังนั้นการ implement rich domain object ก็เป็นเรื่องที่ง่าย แต่มีบางคนที่ไม่ชอบ (Martin Fowler) ที่จะยัดความซับซ้อนลงใน domain object (EJB2 ทำได้ยากนัก) โดยเสนอให้สร้าง service/application layer ที่ทำหน้าที่ business logic ไว้ต่างหาก (service layer มันก็เหมือนกับ business layer แต่มันแค่บางกว่า) ดังนั้นจึงไม่น่าแปลกใจที่จะเห็นการเอา Session bean มาทำหน้าที่เป็น service layer
- Presentation Layer --> [Service Layer] Business Layer --> Persistance Layer --> Database Layer
- Domain-driven design
- Session Bean เป็นที่เก็บ business logic ต่างๆ โดยแบ่งออกเป็น 2 ประเภทคือ
- Stateless ที่จะไม่เก็บสถานะของ client ไว้ข้าม request ควรนำมาใช้งานเช่น ตรวจสอบวงเงิน หรือตรวจสอบว่าลูกค้าเคยซื้ออะไรแล้วบ้าง
- Stateful จะเก็บสถานะของ client ข้าม request ได้เลยจนกว่า client จะ disconnection กับทาง web app เราเช่น transaction ของการซื้อสินค้า online ที่ต้องผ่านหลายหน้ากว่าจะเสร็จ 1 transaction
- Message - Driven beans (MDB) คล้ายกับ session bean ที่เก็บ business เหมือนกันแตกต่างตรงที่ client เรียก MDB ไม่ได้แต่ MDB จะดักจับข้อมูลไปหา MDB Server (i.e. IBM Websphere MQ, Sonic MQ, Oracle Advanced Queueing, TIBCO) โดย MDB จะใช้กับระบบที่เชื่อมต่อกันหรือต้องการทำงานแบบ asynchronous process เช่นส่งรายการสินค้าที่ได้ใหม่ไปที่ระบบ automated retail หรือใช้ในระบบ supply chain management
- Entities and Java Persistence API เป็น feature ที่น่าสนใจของ EJB3 ในส่วนของการจัดการ persistence
- Persistence เป้นความสามารถในการเอาข้อมูลที่อยู่ใน relational database ออกมาเป็น Java Object ใน persistance ของ EJB3 จะจัดการโดยใช้ JPA โดยมันจะใช้เทคนิคที่เรียกว่า ORM การใช้เทคนิคดังกล่าวอาจต้องมีการ config เล็กน้อยเพื่อให้รู้ว่า field ใด map เข้ากับ attribute ใดโดยเราไม่ต้องสนใจว่าจะเขียน code ติดต่อกับ database อย่างไรเพราะ JPA จะจัดการส่วนนี้ให้ ช่วยทำให้ลดเวลา coding และช่วยลดความน่าเบื่อได้
- Framework ที่มีความสามารถของ ORM แบบนี้ไม่ได้เป็น concept ใหม่แต่มันมีมานานแล้วเช่น Oracle Toplink, JBoss Hibernate
- ใน EJB3 ในส่วน Persistence จะใช้ JPA ซึ่งมันมีการกำหนดมาตรฐานดังนี้
- เขียน ORM config metadata เมื่อ mapping กับ relational database
- EntityManager API เป็น API มาตรฐาน ที่เอาไว้ทำ CRUD ให้กับ Entity bean
- Java Persistence Query Language (JPQL) ใช้ค้นหาและส่ง persistence app data
- ตั้งแต่ Java มีการกำหนดมาตราฐาน JPA เพื่อให้เป็นมาตราฐานของ ORM Framework มันทำให้เราสามารถ plugin ORM product อื่นๆ เช่น JBoss Hibernate, Oracle Toplink, BEA Kodo ฯลฯ ภายใต้ JPA ได้
- Entity ถ้าใช้ JPA ในการสร้าง persistence logic เราต้องใช้ entity bean
- ถ้าเรามอง session bean เป็น verb ตัว entity เปรียบได้กับ noun
- EntityManager มันเป็น interface โดยมันจัดเตรียมบริการต่างๆ ให้กับ persistence (CRUD) โดยมันจะอ่าน ORM metadata จาก entity และจัดเตรียมการทำงานต่างๆ ภายใต้ DB ให้ (CRUD) (เพิ่มเติม ข้างใน JPA มีการจัดเตรียมความสามารถในการจัดการ Lifecycle, Performance Turning, Caching และจัดการ Transaction)
- Java Persistence Query Language เป็นสิ่งที JPA จัดเตรียม Query Language ไว้ทำหน้าที่คล้ายกับ SQL ปกติ
เมื่อเราสร้าง Java class มันต้องรันผ่าน JVM นี่ก็เหมือนกันใน EJB session bean, mdb ทำงานอยู่บน ejb container ส่วน entity bean ทำงานบน persistence provider (จริงๆ EJB Container ก็คือ JVM แต่เพิ่มความสามารถเข้าไปเช่น transaction management, security management, remoting, webservice)
- Web Container (deploy: jsp, jsf) สามารถเข้าถึง session bean, entity bean ได้
- EJB Container (deploy: session bean, mdb) สามารถเข้าถึง entity bean ได้
- Persistence provider (deploy: entity bean)
Subscribe to:
Posts (Atom)