Friday 12 October 2007

การจัดการ Error ที่เกิดขึ้นจากการเรียก EJB Client Application บน WS6

การจัดการ Error ที่เกิดขึ้นจากการเรียก EJB Client Application บน WebSphere 6

สำหรับนักพัฒนาที่เริ่มศึกษา EJB ทุกท่าน มักจะพบปัญญาเดียวกันคือ เรียกใช้ EJB instance ไม่ไดั ทั้งที่พิมพ์ตามหนังสือ, เอกสาร, หรือ tutorial ใด ๆ ทุกอย่างแล้ว ก้อยังฟ้อง Error ออกมาให้ปวดอยู่เสมอ

วันนี้ผมจะนำเสนอเกร็ดเล็กเกร็ดน้อย ที่จะช่วยให้ปัญหากวนใจเหล่านี้ หมดไปเสียที

สมมุติว่าเรามี EJB project ที่ ทำการ deploy ขึ้นไปบน Server เรียบร้อยแล้ว จากนั้นเราก้อจะมาทำ ตัว client ที่จะไปเรียก EJB เหล่านั้น กัน

ผมจะจำแนก ตัว client ออกเป็นสองประเภทครับ คือพวกที่รันอยู่บน JVM เดียวกันกับ EJB และ พวกที่รันบน JVM คนละตัวกับ EJB ตรงนี้ถ้าเราทำตามตัวอย่างในหนังสือ, เอกสาร, หรือ tutorial ใด ๆ จะพบว่า จะมีการเรียก InitialContext Class ดังนี้

InitialContext ic = new InitialContex();

นั่นหมายความว่า การทำงานของ client ตัวนี้ รันอยู่บน JVM ตัวเดียวกัน กับ EJB

แต่สำหรับนักพัฒนาสมัครเล่นอย่างผม ซึ่งมักจะลง JDK ไว้หลาย version เหลือเกิน ไม่รู้ตัวไหนบ้างมั่วไปหมด ดังนั้นแล้วจึงมั่นใจได้ว่า JVM ที่ใช้รัน Client เป็นคนละ
ตัวกับที่รัน EJB ผมจึงหันมาใช้ constructor ที่มีการกำหนดค่า ให้ตรงกับ System Enviroment แทน ดังนี้นะครับ

Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY, <factory_Class>); props.put(Context.PROVIDER_URL, <host_name:port>);
InitialContext ic = new InitialContext(props) ;


มาถึงตรงนี้หลายท่านคงสงสัยขึ้นมาบ้าง ว่า <factory_class> ,<hostname:port> เราจะกับหนดค่าอย่างไร อันนี้มันก้อขึ้นอยู่กับว่า เราให้ Application Server อันไหน
เช่น WebSphere, Oracle AS , JBoss, WebLogic เป็นต้น ผมขอยกตัวอย่างที่ผมใช้งานคือ JBoss 4 กับ Websphere 6.0 ดังนี้ครับถ้าเป็น JBoss 4 เราจะเรียกดังนี้ครับ

environment.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");

environment.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");

environment.put(Context.PROVIDER_URL, "jnp://localhost:1098");

// ตรง localhost นี่เปลี่ยนเป็น host ที่ EJB อยู่ในกรณีต่างเครื่อง

// ส่วน port 1098 เป็น default port ของ jboss นะครับ
// ลองเช็คดูได้คับว่าเครื่องเราใช้ port อันไหน เพราะว่าบ่อยครั้งที่ port default ถูกใช้งานไปแล้ว ให้เราลอง
// ตรวจสอบ ใน file jboss-service.xml ตรง tag ที่มีคำว่า name="jboss:service=Naming"
// ก้อให้นำค่าของ port ใน attribute นั้นมาใช้งานครับ

// ส่วนของ Websphere 6 นั้น ดังนี้ครับ


Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY, "com.ibm.websphere.naming.WsnInitialContextFactory");

props.put(Context.PROVIDER_URL, "iiop://localhost:2809";

// เช่นเดียวกันกับ JBoss ครับ port 2809
// นี่เป็น port default ซึ่งผมจะพบเป็น ประจำเลย
// ว่าเครื่องที่รันไม่ได้ port default
// เพราะลง program อะไรต่อมิอะไรเต็มไปหมด
// จึงต้องทำการตรวจสอบ port server ที่แน่นอนก่อนเรียกใช้
// โดยเข้าไปที่ Server Websphere console นะครับ
// แล้วไปที่ Application servers > server1 > Ports

// server1 คือ ชื่อ server ที่เรา deploy EJB ขึ้นไปนั่นเอง ครับ
// โดยดูที่ port name ว่า "BOOTSTRAP_ADDRESS " ในตาราง
// เราก้อจะได้ port ที่ใช้ในการ remote เข้าไปใช้ instance EJB
// ในกรณีที่ใช้ Websphere Server 6 โดยจะนำ properties นี้
// ไปเป็น argument ให้กับ InitialContext class ดังที่กล่าวไปข้างต้นแล้ว
// ดังนี้ครับ InitialContext ic = new InitialContext(props) ;

// หลังจากนั้น เราก้อจะมาทำการ lookup JNDI
// ของ bean ที่เราต้องการใช้งานนะครับ
// ถ้าเราอ่านดูในหนังสือทั่วไปจะเป็นดังนี้นะครับ
Object o = ic.lookup("java:comp/env/ejb/MyHelloBean");

// MyHelloBean คือชื่อ ของ JNDI Name ที่ประกาศไว้ใน ejb-jar.xml
// แต่กรณีนี้จะใช้ได้กับ JVM เดียวกันเท่านั้นนะครับ กรณีที่เป็น JVM ต่างกัน
// จะไม่รู้จัก java:comp ดังนั้น เราจะต้องเรียกใช้ JNDI name ตรง ๆ
// ดังที่ประกาศไว้ใน ejb-jar.xml ครับ
// (กรณีที่เป็น Websphere 6 จะเป็นชื่อเฉย ๆ เช่น MyHelloBean )
// ดังนั้นโค๊ดของเราจะกลายเป็นดังนี้ครับ
Object o = ic.lookup("MyHelloBean") ;


ส่วนที่เหลือก้อตามโค๊ดในหนังสือ, เอกสาร, หรือ tutorial ใด ๆ ซึ่งถ้าเราพิมพ์ถูกไม่ตกหล่น ก้อไม่น่าจะมีปัญหาอะไรอีกแล้วล่ะครับ หรือถ้าเพื่อน ๆ ท่านใด ยังเจอปัญหา หรือ สงสัยก้อ comment เพิ่มเติมมาได้นะครับ แล้วพบกันใหม่ในบทความถัดไป

No comments: