หน้าเว็บ

วันอาทิตย์ที่ 18 พฤษภาคม พ.ศ. 2557

JSF notification - notify phase : java



        ผมใช้ JSF มาได้ 2 ปี แล้วครับ จึงเกิดความคุ้นเคยในระดับนึง  ใช้ไปใช้มา  ก็เริ่มเห็นข้อบกพร่อง ของ code ที่ตัวเองเขียน  รู้สึกว่าบางอย่าง  มันยังดูซ้ำซ้อน หรือใช้ยากไป  เราสามารถลดมันลงได้อีกมั้ย ทำให้มันง่ายกว่านี้ได้มั้ย ใช้ของเดิมที่เคยมีอยู่แล้วได้มั้ย  ช่วงนี้ผมก็เลยค่อยๆ เริ่มเขียน library สำเร็จรูปเอาไว้ใช้งานภายในบริษัทครับ  อย่างตัวอย่างวันนี้  ผมเขียนตัว notify phase (<p:grlow/> ของ primefaces)  ซึ่งมันจะจัดการ notify กลับไปยัง client (browser) ให้เองโดยอัตโนมัต เมื่อมันทำงานเสร็จ เราไม่ต้องมาคอย check if else ว่าเมื่อ code ทำงานสำเร็จให้แจ้ง success หรือ code ทำงานผิดพลาดให้แจ้ง fail เดี๋ยว notify phase จะจัดการให้เองครับ

        code จะมีลักษณะเป็น callback method ซึ่งมันก็จะประมวลผลตาม phase หรือลำดับ ที่เราได้กำหนดไว้ ดังนี้


1. เรียก method process (require implement) เพื่อทำการประมวลผล business logic ที่เราได้ define ไว้
2. เมื่อ code ทำงานเสร็จ
  • ไม่มี Exception มันจะไปทำงานที่ getSuccessBody (optional) เพื่อดึง message ที่แจ้งเตือนว่า code ทำงานถูกต้อง / เสร็จสิ้นแล้ว กลับไปยัง user
  • มี Exception มันจะไปทำงานที่ getErrorBody (optional) เพื่อดึง message ที่แจ้งเตือนว่า code ทำงานผิดพลาด กลับไปยัง user
3. สุดท้าย มันจะไปเรียกที่ onFinally  (optional) ครับ  เพื่อทำงานอะไรบางอย่าง เมื่อประมวลผล business logic เสร็จ (ไม่ว่าจะประมวลผลสำเร็จ หรือ ผิดพลาดก็ตาม  มันจะถูกเรียกเสมอ)


ทำไม ผมต้องใช้ Notify phase ?
  • บางที เราอาจจะอยากเปลี่ยน message ของ Exception ที่เป็นภาษาโปรแกรมมิ่ง (user อ่านไม่เข้าใจ) ให้เขาอ่านเข้าใจได้ เช่น OptimisticLockingException ... ผมว่าเขาคงไม่รู้หรอกว่ามันคืออะไร  หน้าที่ของเราคือแปลงข้อความนี้ ไปให้ user อ่านเข้าใจครับ  ซึ่งเราสามารถดักไว้ที่ getErrorBody() ได้
  • ลด code ซ้ำซ้อน ที่เราเขียนเหมือนๆ กันไว้ในหลายๆ ที่  
  • สามารถแก้ได้จากที่เดียว
  • นำ code กลับมาใช้งานใหม่ได้  เพราะเราเขียนเป็น library ไว้ 
มาดู code จริงๆ กันครับ

JSFNotification.java
package com.blogspot.na5cent.jsflibrary.util;

import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author redcrow
 */
public class JSFNotification {

    private static final Logger LOG = LoggerFactory.getLogger(JSFNotification.class);

    public static void notifyClient(FacesMessage.Severity messageType, String title, String body) {
        FacesContext context = FacesContext.getCurrentInstance();
        context.addMessage(null, new FacesMessage(messageType, title, body));
    }

    public static void notifyPhase(NotifyCallback callback) {
        try {
            callback.process();
            notifyClient(FacesMessage.SEVERITY_INFO, callback.getTitle(), callback.getSuccessBody());
        } catch (Throwable ex) {
            LOG.warn(null, ex);
            notifyClient(FacesMessage.SEVERITY_ERROR, callback.getTitle(), callback.getErrorBody(ex));
        } finally {
            callback.onFinally();
        }
    }
}
NotifyCallback.java
package  com.blogspot.na5cent.jsflibrary.util;

/**
 * @author redcrow
 */
public abstract class NotifyCallback {

    private final String title;

    public NotifyCallback(String title) {
        this.title = title;
    }

    public String getTitle() {
        return title;
    }

    public String getSuccessBody() {
        return "เสร็จเรียบร้อย";
    }

    public String getErrorBody(Throwable ex) {
        return "ล้มเหลว เนื่องจาก " + ex.getMessage();
    }

    public abstract void process() throws Throwable;

    public void onFinally() {
        //
    }
}
ตัวอย่างการใช้งาน ที่ method ของ managed bean หรือ controller
.xhtml
<p:growl id="notification"/>

<p:commandButton value="เพิ่ม"
                 actionListener="#{prestigeController.onAdd()}"
                 update=":notification"/>
PrestigeController.java
...
...
...
import com.blogspot.na5cent.jsflibrary.util.JSFNotification;
import com.blogspot.na5cent.jsflibrary.util.NotifyCallback;
...
...
...
    public void onAdd() {
        JSFNotification.notifyPhase(new NotifyCallback("การเพิ่มข้อมูลเกียรติประวัติ") {

            @Override
            public void process() throws Throwable {
                if (uploaded) {
                    PrestigeAttachFile attachFile = crateAttachFile();
                    copyFile2Temporary(attachFile);
                    transfer2PrestigeInfo(attachFile);
                }

                prestigeInfo.setHcode(profileContext.getProfile().getHcode());
                prestigeInfo.setPrestige(selectedPrestige);
                prestigeInfo.setProfile(profileContext.getProfile());
                prestigeInfoService.save(prestigeInfo);
            }

            @Override
            public void onFinally() {
                reloadTab();
            }
        });
    }
...
...
...


ที่มาของภาพประกอบ http://www.bitsmonkey.com/2011/07/notify-async-operation-in-c.html

ไม่มีความคิดเห็น:

แสดงความคิดเห็น