November 10, 2011

Servlet Listener

ကျွှန်တော်သည် မြန်မာအိုင်တီပရိုတွင် ဤလွယ်ကူသော ဆာဗလက်များ အကြောင်းကို အခန်းဆက်ဖြင့် ရေးသားနေခဲ့ပါသည်။ သို့ရာတွင် အလုပ်များနေသည်ကတစ်ကြောင်း မြန်မာအိုင်တီပရိုဘလောဂ်၏ စာလုံးအပြောင်းအလည်းကြောင့် စာမရေးဖြစ်သည်ကတစ်ကြောင်း၊ အစရှိသည့်အကြောင်းကြောင်းကြောင့် ကျွှန်တော့်ဘလောဂ်ကို တစ်ခြားတနေရာရာကို ရွှေ့ရန်ဆုံးဖြတ်ခဲ့ပါသည်။ သည်လိုနှင့် Google ၏ Blogspot ကို သွားတွေ့ပြီး ဤနေရာတွင် စာရေးသားသွားရန် ဖြစ်လာခဲ့ပါသည်။

အစတွင် မြန်မာအိုင်တီပရိုတွင် ရေးသားခဲ့သော ရေးလက်စ အကြောင်းအရာများကို ရွှေ့နေခဲ့ပါသည်။ ပြီးခဲ့သော Servlet ဖြင့် AOP ကို ရေးပြီးချိန်တွင် မြန်မာအိုင်တီပရိုတွင် ရေးခဲ့သော အကြောင်းများ ကုန်ပြီဖြစ်ပါသဖြင့် အခန်းဆက်ကို စတင်ရေးသားသွားမည် ဖြစ်သည်။

ဤတစ်ခေါက်ရေးသားသွားမည့်အကြောင်းမှာ ServletListener အကြောင်းပဲဖြစ်ပါသည်။ FrameWork များကိုအသုံးများလာသောယနေ့ခေတ်မှာ ServletListener များကို ကိုယ်တိုင်ရေးသားသူနည်းပါမည် ဟုထင်ပါသည်။

ServletListener ကင်းစောင့်သူများနှင့် တူ၏။ စောင့်ကြည့်နေသော Event တစ်ခုဖြစ်ပေါ်လာပါက သူလုပ်စရာရှိသည့် အလုပ်တာဝန်များကို သူ့အလိုလို ထမ်းဆောင်သွားမည် ဖြစ်သည်။ ServletListener များအား စောင့်ကြည့်နေသော Object များအပေါ်တွင် မှုတည်၍ အဓိကအားဖြင့် ၃မျိုးခွဲခြားနိုင်၏။
  1. ServletContext
  2. ServletRequest
  3. HttpSession

ServletContextListener

ServletContextListener များသည် ServletContext ၏ Event များကို စောင့်ကြည့်နေပြီး WebApplication ၏ Servlet များ၏ Lifecycle ပြောင်းလည်းမှု့များတွင် အသုံးပြုနိုင်၏။ ဥပမာ အားဖြင့် WebApplication တစ်ခုတွင် ကုဒ်စာရင်းများကို အသုံးပြုသည်ဆိုကြပါဆို့။ ထိုကုဒ်များကို ဆာဗလက်များထဲတွင် တိုက်ရိုက်လည်းရေမထားချင်ဘူး။ ဘာလို့လည်းဆိုတော့ အသုံးပြုမည့် လော့ဂျစ်နဲ့မဆိုင်တဲ့အတွက် အစတစ်ခါ ခေါ်ယူထားပြီးလျှင် အကြိမ်ကြိမ် အသုံးပြုသွားလိုပါသည်။ ပြောင်းလည်းရန်လည်း အစီအစဉ်မရှိ။ ထိုအခါမျိုးတွင် ServletContextListener သည် လွန်စွာအစဉ်ပြေ၏။

ဆာဗလက်ကို initialize လုပ်သည့်အခါတွင် အလုပ်လုပ်နိုင်မည့် Listener တစ်ခုကိုရေထားပြီး၊ ထို Listener မှ လိုအပ်သော ကုဒ်များကို Properties များမှ၎င်း၊ ဒေတာဘေစ်များမှ၎င်း ခေါ်ယူပြီး မံမိုရီပေါ်တင်ထားပါက ထိုဆာဗလက် တသက်တာ တောက်လျှောက်အသုံးပြုသွားနိုင်မည် ဖြစ်၏။
ဤServletContextListener သည် Servlet LifeCycle များကို စောင့်ကြည့်နေပါသဖြင့် Servlet မစတင်ခင်၊ ဒါမှမဟုတ် Servlet ပြီးဆုံးသည့်အခါများတွင် လုပ်ဆောင်စေလိုသည့်အရာများကို ရေးသားထားပါက စောင့်ကြည့်နေသော Servlet ကစတင်သည့်အခါတွင်၎င်း၊ ပြီးဆုံးသည့်အခါတွင်၎င်း သူ့အလိုလိုအလုပ်လုပ် နိုင်မည်ဖြစ်၏။

တဖန် ServletContextAttributeListener သည် ServletContextAttribute များကို စောင့်ကြည့်နေပါသဖြင့် Application Scope တွင် အချက်အလက်အသစ်များကို သိမ်းဆည်းသည့်အခါတွင်၎င်း၊ အချက်အလက်များကို ပြောင်းလည်းသည့်အခါတွင်၎င်း၊ အချက်အလက်များကို ဖျက်သိမ်းရာတွင်၎င်း သိရှိပြီး အလုပ်လုပ်နိုင်ပါသည်။

အင်တာဖေစ်လုပ်ဆောင်ချက်များအသုံးပြုပုံ/ရှင်းလင်းချက်များ
javax.servlet.ServletContextListenercontextInitializedWeb Application များကို စတင် ခေါ်ယူသည့် အခါတွင် ခေါ်ပါသည်။ Filter နှင့် Servlet#init ကို မခေါ်ယူခင် ခေါ်ယူပါသည်။
contextDestroyedWeb Application များကို အဆုံးသတ်သည့် အခါ များတွင် ခေါ်ယူပါသည်။ Filter နှင့် Servlet#destroy ၏ နောက်တွင် ခေါ်ယူပါသည်။
javax.servlet.ServletContextAttributeListener attributeAdded ServletContext တွင် ServletContext#serAttrivute လုပ်ဆောင်ချက်ဖြင့် Attribute တစ်ခုကို ဖြည့်စွက်သည့်အခါတွင် ခေါ်ယူပါလိမ့်မည်။
attributeReplaced ServletContext#serAttrivute လုပ်ဆောင်ချက်ဖြင့်  ရှိရင်းစွဲ Attribute တစ်ခုကို အစားထိုး ပြောင်းလည်းသည့်အခါတွင် ခေါ်ယူပါလိမ့်မည်။
attributeRemoved ServletContext#removeAttribute ဖြင့် Attribute တစ်ခုကို ဖျက်စီးပစ်သည့်အခါတွင် ခေါ်ယူပါလိမ့်မည်။


ServletRequestListener

ServletRequestListener များသည် ServletRequest Object များ၏ Event များကို စောင့်ကြည့်နေသော Listener များဖြစ်ကြ၏။ ServletRequestListener နှင့် ServletRequestAttributeListener Interface များမှ အသုံးပြုနိုင်ပါသည်။

ServletRequestListener ဖြင့် ServletRequest Object ၏ စတင်ခေါ်ယူသည့်အခါတွင်၎င်း၊ နောက်ဆုံး အသုံးမလိုတော့သည့် အခါ မံမိုရီအပေါ်မှ ဖျက်စီးပစ်သည့်အခါတွင်၎င်း လုပ်ဆောင်ချက်များကို ဖြည့်စွက်ရေးသားနိုင်၏။ တဖန် ServletRequestAttributeListener အင်တာဖေစ်ကို အသုံးပြုခြင်းအားဖြင့် ServletRequest Object တွင် Attribute များကို ဖြည့်စွက်သည့်အခါတွင်၎င်း၊ အစားထိုး ပြောင်းလည်းသည့် အခါတွင်၎င်း၊ ဖျက်စီးပစ်သည့်အခါတွင်၎င်း လုပ်ဆောင်ချက်များကို ဖြည့်စွက်ရေးသားနိုင်သည်။


အင်တာဖေစ်လုပ်ဆောင်ချက်များအသုံးပြုပုံ/ရှင်းလင်းချက်များ
javax.servlet.ServletRequestListener requestIntialized HTTP Request Object အား init လုပ်သည့်အခါတွင် ခေါ်ယူပါမည်။
Request အားခေါ်ယူပြီး Filter များအား မခေါ်ယူခင် ခေါ်ယူပါမည်။
requestDestroyed HTTP Request Object အား အသုံးမလိုတော့၍ ဆာဗာမံမိုရီအပေါ်မှ ဖျက်စီးပစ်သောအခါတွင် ခေါ်ယူပါမည်။  Filter များအား ခေါ်ယူပြီနောက်တွင် ခေါ်ယူပါမည်။
javax.servlet.ServletRequestAttributeListener attributeAdd ServletRequest#setAttributeဖြင့် Attribute တစ်ခုအား အသစ် ဖြည့်စွက်လိုက်သည့် အခါတွင် ခေါ်ယူပါမည်။
attributeReplaced ServletRequest#setAttributeဖြင့် ရှိရင်စွဲ Attribute တစ်ခု၏ တန်ဖိုးအား ပြောင်းလည်း သတ်မှတ်သည့် အခါများတွင် ခေါ်ယူပါမည်။
attributeRemoved ServletRequest#removeAttributeဖြင့် ရှိရင်းစွဲ Attribute တစ်ခုအား ဖျက်ပစ်လိုက်သည့်အခါတွင် ခေါ်ယူမည် ဖြစ်၏။ သို့ရာတွင် Attribute မှာ ဖျက်စီးပြီးဖြစ်သည့် အခါတွင်၎င်း၊ မရှိခဲ့ရင်၎င်း ခေါ်ယူမည် မဟုတ်ပေ။



HttpSessionListener

အမည်အတိုင်း HttpSession Object ၏ ပြောင်းလည်းမှု့ အခြေအနေများကို စောင့်ကြည့်ပြီး အလုပ်လုပ်နိုင်သော Listener များဖြစ်ကြ၏။

HttpSession Object အား စတင်ခေါ်ယူသည့်အခါတွင်၎င်း၊ ဖျက်စီးပစ်သည့်အခါတွင်၎င်း HttpSessionListener အင်တာဖေစ်ကို အသုံးပြုနိုင်၏။ တဖန် HttpSession တွင် Attibute များအား သတ်မှတ်သည့်အခါတွင်၎င်း၊ ပြောင်းလည်းသည့် အခါတွင်၎င်း၊ ဖျက်စီးသည့် အခါတွင်၎င်း HttpSessionAttributeListener အင်တာဖေစ်ကို အသုံးပြုနိုင်ပါသည်။

 ထို့ထက်မက Application Server များအား Cluster အနေဖြင့်အသုံးပြုသည့် စစ္စတမ်များတွင် ဆက်ရှင်များအား ဆာဗာတစ်ခုမှ အခြားဆာဗာတစ်ခုအား လက်ကမ်းပြောင်းလည်းပေးသည့် အခါတွင်၎င်း၊ ဆာဗာအား ခေတ္တနားသည့်အခါ ဆက်ရှင်အချက်အလက်များအား ခေတ္တသိမ်းဆည်းသည့်အခါ မျိုးတွင်၎င်း ဆာဗာအား ပြန်လည်စတင်၍ ယခင်အသုံးပြုခဲ့သော ဆက်ရှင်အချက်အလက်များအား ပြန်လည်ခေါ်ယူသည့်အခါမျိုးတွင်၎င်း HttpSessionActivationListener အင်တာဖေစ်ကို အသုံးပြုနိုင်၏။


အင်တာဖေစ်လုပ်ဆောင်ချက်များအသုံးပြုပုံ/ရှင်းလင်းချက်များ
java.servlet.http.SessionListener sessionCreated Session အား စတင်ခေါ်ယူသည့်အခါမျိုးတွင် ခေါ်ယူပါမည်။ Request မှ getSession(true) အား ခေါ်ယူသည့်အခါတွင် ခေါ်ယူပါသည်။
sessionDestroyed HttpSession#invalidate ဖြင့် Session အား ဖျက်စီးသည့် အခါမျိုးတွင်၎င်း၊ session timeout ဖြစ်သည့်အခါတွင်၎င်း  ခေါ်ယူပါသည်။
Servlet 2.3 တွင် Session အား ဖျက်စီး ပစ်ပြီးနောက် ခေါ်ယူခဲ့သော်လည်း 2.4 မှစ၍ Session အား ဖျက်စီးပစ်မည့် လုပ်ဆောင်ချက်အား မခေါ်ယူခင် ခေါ်ယူရန် ပြောင်းလည်းခဲ့၏။
java.servlet.http.SessionAttributeListener attributeAdded HttpSession#setAttribute အား အသုံးပြု၍ ဆက်ရှင်တွင် တန်ဖိုးအသစ်တစ်ခု သိမ်းဆည်းသည့် အခါတွင် ခေါ်ယူပါသည်။
attributeReplaced HttpSession#setAttribute အား အသုံးပြု၍ ဆက်ရှင်တွင် ရှိပြီးသား တန်ဖိုးတစ်ခုအား ပြောင်းလည်း သတ်မှတ်သည့် အခါတွင် ခေါ်ယူပါသည်။
attributeRemoved HttpSession#removeAttributeဖြင့် ဆက်ရှင်တွင် ရှိသော တန်ဖိုးတစ်ခုအား ဖျက်ထုတ်ပစ်သည့် အခါတွင် ခေါ်ယူပါသည်။
java.servlet.http.SessionActivationListener sessionWillPassivate Session Object အား Active အနေအထားမှ ရပ်နားပစ်သည့်အခါ၊ Serialized မလုပ်ခင် အခါမျိုးမှာ ခေါ်ယူပါသည်။
Application Server အားရပ်နား သည့်အခါ မျိုးတွင် ဆက်ရှင် အချက်အလက်များအား Serialize လုပ်၍ သိမ်းဆည်းပါသည်။ ထို့အပြင် Application Server အများကို Cluster အနေနှင့် အသုံးပြု၍၊ ဆာဗာတစ်ခုမှ အခြားသော ဆာဗာတစ်ခုအား ဆက်ရှင်အချက်အလက်များကို ကူးပြောင်းပေးရန် Serialize လုပ်သည့်အခါများတွင် ခေါ်ယူပါသည်။ 
sessionDidActivate ဆက်ရှင်အား ပြန်လည် Active ဖြစ်စေသည့်အခါ၊ Serialize လုပ်ထားသော ဆက်ရှင်အား ဆက်ရှင် Object အနေအဖြင့် ပြန်လည်ခေါ်ယူသောအခါ များတွင် ခေါ်ယူပါသည်။
Cluster ကို အသုံးပြုထားသော စစ္စတမ်များတွင် ဆာဗာတစ်ခုမှ Serialize လုပ်၍ လက်ဆင့်ကမ်းလာသော အချက်အလက်ဖိုင်ကို မံမိုရီအပေါ်ခေါ်ယူ၍ ဆက်ရှင်Object အဖြစ်ပြန်လည် အသုံးပြုသည့် အခါတွင် ခေါ်ယူပါသည်။
java.servlet.http.SessionBindingListener valueBound ဆက်ရှင်တွင် တန်ဖိုးတစ်ခု bind လုပ်သည့်အခါမျိုးတွင် ခေါ်ယူပါမည်။ HttpSession#setAttribute ကို ခေါ်ယူသည့်အခါမျိုးတွင် ခေါ်ယူပြီး၊ SessionAttributeListener#attributeAdded ၏ ရှေ့တွင် ခေါ်ယူပါသည်။
valueUnbound ဆက်ရှင်တွင် တန်ဖိုးတစ်ခု unbind လုပ်သည့်အခါမျိုးတွင် ခေါ်ယူပါမည်။ HttpSession#setAttribute ဖြင့် ရှိပြီးသား Attribute တစ်ခုအား အစားထိုးသည့်အခါ၊ HttpSession#removeAttribute ကို ခေါ်ယူသည့်အခါမျိုးတွင် ခေါ်ယူပြီး၊ SessionAttributeListener#attributeAdded နှင့် SessionAttributeListener#attributeRemoved ၏ ရှေ့တွင် ခေါ်ယူပါသည်။


လက်တွေ့ရေးသားကြည့်ခြင်း

လက်ရှိ အသုံးပြုနေသူများကို စောင့်ကြည့်ရေတွက်နိုင်သည့် အပလီကေးရှင်းတစ်ခုကို လစ္စနာကို အသုံးပြု၍ ရေးကြည့်ပါမည်။ ဤနမှုနာအတွက် ရေးသားသွားမည်မှာ အောက်ပါအတိုင်း ဖြစ်၏။
  • UserCountListener
  • CounterBean
  • UserCounterServlet
  • episode6.html

UserCountListener သည် ဆက်ရှင်များကို စောင့်ကြည့်နေသော ဆက်ရှင်လစ္စနာ ဖြစ်ပြီး၊ အတွင်းပိုင်းတွင် လူဦးရေကို မှတ်သားနိုင်သော CounterBean Object ကို ပိုင်ဆိုင်၏။ ဆက်ရှင်တစ်ခုကို စတင်ခေါ်ယူအသုံးပြုပါက CounterBean ၏ increase ကို ခေါ်ယူပြီး ဆက်ရှင်တွင် မှတ်သားထားမည် ဖြစ်သည်။ တဖန် ဆက်ရှင်အား အသုံးမပြုတော့ပါက CounterBean ၏ decrease ကို ခေါ်ပြီး လူဦးရေကို လျှော့မှတ်ပါမည်။

UserCountListener.java
public class UserCountListener implements HttpSessionListener {
 
 private CounterBean counter = new CounterBean();

 @Override
 public void sessionCreated(HttpSessionEvent event) {
  this.counter.increase();
  event.getSession().setAttribute("user-count", this.counter);
 }

 @Override
 public void sessionDestroyed(HttpSessionEvent event) {
  this.counter.decrease();
 }
}

CounterBean သည် အသုံးပြုသူအရေအတွက်ကို မှတ်သားနိုင်သော Object ဖြစ်၏။ ဆာဗလက်လစ္စနာများသည် Single Thread Object များဖြစ်ပြီး အခြားသော Thread အမျိုးမျိုးမှ ခေါ်ယူအသုံးပြုလေ့ရှိ၏။ ထို့အတွက် အမှတ်မမှားစေရန် Thread Save ဖြစ်စေရန် သတိထားပြီး ရေးသားရန်လိုအပ်၏။ အသုံးပြုနေသော နမှုနာတွင် syncronized ကို အသုံးပြု၍ Thread များအကြားတွင် တူညီသော အခြေအနေကို ထိမ်းသိမ်းထားနိုင်ရန် စီမံနေခြင်းဖြစ်သည်။

public class CounterBean {
 private int count = 0;
 
 public int getCount() {
  return this.count;
 }
 
 public synchronized void increase() {
  this.count ++;
 }
 
 public synchronized void decrease() {
  this.count --;
 }
}

တဖန် ဆာဗလက်လစ္စနာ ကလပ်စ် တစ်ခုကို ရေးသားပြီးလျှင် web.xml တွင်ရေးသားရန်လိုအပ်ပါသည်။ Filter များ သတ်မှတ်ချက်ပြီးလျှင် Listener ၏သတ်မှတ်ချက်ကို ရေးသားရန်လိုအပ်ပြီး၊ ရေးသားပုံမှာ အောက်ပါအတိုင်းဖြစ်၏။ လစ္စနာ တဂ်အတွင်းတွင် အသုံးပြုလိုသည့် ကလပ်စ်ကို ရေးသားရုံဖြင့် အသုံးပြုနိုင်မည် ဖြစ်၏။ UserCounterListener သည် HttpSessionListener ကို ပံ့ပိုးထားပါသဖြင့် ဤ Web Application တစ်ခုလုံးတွင် လစ္စနာ အနေဖြင့် အသုံးပြုနိုင်ပါမည်။
 <listener>
  <listener-class>com.episode6.UserCountListener</listener-class>
 </listener>

Web Application အတွင်း Session တစ်ခုကို ခေါ်ယူတိုင်း အထက်ပါ လစ္စနာက အလိုအလျှောက် အလုပ်လုပ်သွားမည် ဖြစ်၏။ ထိုနည်း၎င်း ဆက်ရှင်တစ်ခုကို ဖျက်သိမ်းတိုင်းလည်း အလုပ်လုပ်သွားပါမည်။ တကယ်ဆိုရင် အဓိကလိုအပ်သည်မှာ UserCountListener.java နှင့် CounterBean.java တို့သာ ဖြည်၏။ သို့ရာတွင် လစ္စနာ၏ အလုပ်လုပ်ပုံကို သိရှိစေရန်  UserCounterServlet.java နှင့်  episode6.html ကိုလည်း ရေးသားထားပါသည်။

UserCounterServlet.java သည် ဆက်ရှင်အတွင်းတွင် ရှိသော CounterBean ကို ခေါ်ယူပြီး လက်ရှိလူဦးရေကို စာမျက်နှာပေါ်တွင်ရေးသားနေပြီး၊ episode6.html သည် UserCounterServlet.java ကိုခေါ်ယူသော လင့်ခ်ကိုသာရေးသားထားပါသည်။

@Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp)
   throws ServletException, IOException {
  CounterBean counter = (CounterBean) req.getSession(true).getAttribute(
    "user-count");
  if (null != counter) {
   resp.getWriter().write(
      new StringBuilder("ယခုအသုံးပြုနေသူ ဦးရေမှာ ")
      .append(counter.getCount())
      .append("ယောက် ဖြစ်ပါသည်။").toString());
  } else {
   resp.getWriter()
      .write("ဘရောင်ဇာသတ်မှတ်ချက်ကို ဆက်ရှင်အားလက်ခံနိုင်ရန် သတ်မှတ်ထားရန်လိုအပ်ပါသည်။");
  }
 }

အထက်ပါ ဆာဗလက်အတွင်းတွင် req.getSession(true) ဖြင့် ဆက်ရှင်ကို စတင်ခေါ်ယူနေ၏။ ထိုအခါ စောင့်ကြည့်နေသူ လစ္စနာက အလုပ်ထလုပ်ပြီး အသုံးပြုသူကို တိုးမှတ်ပါမည်။ ပြီးလျှင် ရှိပြီးသား ဆက်ရှင်တွင် user-count အမည်ဖြင့် သိမ်းထားမည်ဖြစ်၏။ တဖန် ဆာဗလက်ထဲမှ ရရှိလာသော ဆက်ရှင်မှ getAttribute("user-count") ဟု သိမ်းထားသော CounterBean Object ဖြစ်သော counter ကို ခေါ်ယူ၏။ counter က null မဟုတ်ခဲ့ပါက counter.getCount() ဖြင့် အသုံးပြုနေသူကို ခေါ်ယူဖော်ပြနေခြင်း သာဖြစ်၏။


လက်တွေ့စမ်းသပ်ကြည့်ခြင်း

လက်တွေ့ရေးထားသော နမှုနာကို စမ်းကြည့်ပါဦးမည်။


အထက်ပါစာမျက်နှာမှ လစ္စနာ နမှုနာ ဆိုသည့်လင့်ခ်ကို နှိပ်ကြည့်ပါက ရေးသားထားသော ဆာဗလက်ကို ခေါ်ယူမည်ဖြစ်ပြီး၊ ဆက်ရှင်ကိုပါ တစ်ခါတည်း ခေါ်ယူမည်ဖြစ်သောကြောင့် ဆက်ရှင်လစ္စနာကို အလုပ်လုပ်စေမည် ဖြစ်ပါသည်။ လင့်ခ်ကို နှိပ်၍တွေ့မြင်ရသော စာမျက်နှာမှာ အောက်ပါအတိုင်းဖြစ်၏။


နမှုနာ Source များကို မြန်မာအိုင်တီပရို ကျူတိုရီရယ်ပရိုဂျက်တွင် လေ့လာနိုင်ပါသည်။

ကိုးကားများ
http://www.ne.jp/asahi/hishidama/home/tech/java/servlet/listener.html
http://docs.oracle.com/javaee/6/api/overview-summary.html

လေးစားစွာဖြင့်
မင်းလွင်

No comments:

Post a Comment