Tuesday, January 03, 2006

Beehive

Beehive เดิมเป็น product ของ BEA
ต่อมาก็เปิดเป็น opensource ภายใต้ project ของ apache group

Beehive เป็น Framework ที่ต่อยอดจาก Struts 1.1
โดยเพิ่มเติม feature เหล่านี้ลงไป
  • Page Flows
    มีการจัดกลุ่ม flow ให้เป็น 1 flow ต่อ 1 controller
    เมื่อ gen เป็น struts แล้ว จะเทียบได้เป็น 1 flow ต่อ 1 struts module
    นอกจากนี้ยังสามารถทำ nested flow ได้ด้วย
  • Controls
    แนวเดียวกับ Spring
    ก็คือ ใช้ POJO มาจับ business logic
  • Web Services
    อันนี้ไม่พิสดารอะไร แค่ mapping POJO เป็น web service


ประเด็นที่น่าสนใจมาก ก็คือ
มีการนำ Annotation มาใช้แทนที่ configuration file แบบเดิมๆที่เป็น xml file
โดย Beehive ใช้ Annotation Processing Tool เข้ามาช่วยในการ
generate struts-config file

ผลที่ได้ จัดได้ว่าไม่เลยทีเดียว
แค่เปิด controller class ดูตัวเดียว ก็เห็น flow ทั้งหมดของมันใน shot เดียว
ไม่ต้องไปไล่เปิดดูใน struts-config.xml เหมือนเมื่อก่อน
ลองดูตัวอย่างที่ผมทำตาม tutorial ดู
package user;
import org.apache.beehive.netui.pageflow.Forward;
import org.apache.beehive.netui.pageflow.PageFlowController;
import org.apache.beehive.netui.pageflow.annotations.Jpf;

import shared.SharedFlow;

@Jpf.Controller(
simpleActions={
@Jpf.SimpleAction(name="begin", path="/user/index.jsp"),
@Jpf.SimpleAction(name="toRegist", path="/user/regist.jsp")
},
sharedFlowRefs={
@Jpf.SharedFlowRef(name="shared", type=SharedFlow.class)
}
)
public class Controller extends PageFlowController {
@Jpf.SharedFlowField(name="shared")
private SharedFlow shareFlow;

private UserForm userForm;

@Jpf.Action(
forwards={
@Jpf.Forward(name="success", path="/user/display.jsp")
},
validatableProperties = {
@Jpf.ValidatableProperty(
propertyName = "name",
displayName = "Name",
validateRequired = @Jpf.ValidateRequired(),
validateMaxLength = @Jpf.ValidateMaxLength(chars = 30)),
@Jpf.ValidatableProperty(
propertyName = "age",
displayName = "Age",
validateRequired = @Jpf.ValidateRequired(),
validateRange = @Jpf.ValidateRange(minInt = 0, maxInt = 130))
},
validationErrorForward =
@Jpf.Forward(name="fail", navigateTo=Jpf.NavigateTo.currentPage)
)
public Forward processData(UserForm form) {
getRequest().setAttribute("data", form);
return new Forward("success");
}

@Jpf.Action(
useFormBean = "userForm",
forwards = {
@Jpf.Forward(name="getCompanyFlow",
path="/company/getCompany.do")
},
doValidation=false
)
protected Forward getCompany(UserForm form) {
return new Forward("getCompanyFlow");
}

@Jpf.Action(
forwards= {
@Jpf.Forward(name="success",
navigateTo=Jpf.NavigateTo.currentPage)
}
)
protected Forward companySelected(String company) {
userForm.setCompany(company);
Forward success = new Forward("success", userForm);
return success;
}

}

Note: จะเห็นว่ามี private instance ที่เป็น formbean อยู่ใน controller ด้วย
อันนี้ใช้ keep ค่าไว้ในกรณีที่เรามีการ flow ไปหลาย screen หรือ กระโดดไปทำงานใน subflow

จาก controller ข้างบน Beehive ก็จะ gen เป็น struts-config ให้
หน้าตาประมาณนี้
  <form-beans>
<form-bean className="org.apache.beehive.netui.pageflow.config.PageFlowActio
nFormBean" name="userForm" type="org.apache.beehive.netui.pageflow.internal.AnyB
eanActionForm">
<set-property property="actualType" value="user.UserForm"/>
</form-bean>
...

<action-mappings>
<action className="org.apache.beehive.netui.pageflow.config.PageFlowActionMa
pping" parameter="user.Controller" path="/begin" scope="request" type="org.apach
e.beehive.netui.pageflow.internal.FlowControllerAction" validate="false">
<set-property property="readonly" value="true"/>
<set-property property="simpleAction" value="true"/>
<set-property property="defaultForward" value="_defaultForward"/>
<forward contextRelative="true" name="_defaultForward" path="/user/index.j
sp"/>
</action>
<action className="org.apache.beehive.netui.pageflow.config.PageFlowActionMa
pping" name="string" parameter="user.Controller" path="/companySelected" scope="
request" type="org.apache.beehive.netui.pageflow.internal.FlowControllerAction"
validate="false">
<set-property property="formClass" value="java.lang.String"/>
<forward className="org.apache.beehive.netui.pageflow.config.PageFlowActio
nForward" name="success" path="currentPage">
<set-property property="returnToPage" value="true"/>
</forward>
</action>
.....
</action-mappings>

<controller className="org.apache.beehive.netui.pageflow.config.PageFlowContro
llerConfig" inputForward="true" processorClass="org.apache.beehive.netui.pageflo
w.PageFlowRequestProcessor">
<set-property property="isReturnToActionDisabled" value="true"/>
<set-property property="sharedFlows" value="shared=shared.SharedFlow"/>
<set-property property="controllerClass" value="user.Controller"/>
<set-property property="isMissingDefaultMessages" value="true"/>
</controller>


ถ้าลองไปอ่าน source code ส่วน generate ของมัน ก็จะยิ่งสนุก
เขาใช้ Velocity เป็น template engine

อ้อลืมบอกไป นอกจากเพิ่มส่วน pageflow ลองไปแล้ว
Beehive ก็มี set ของ taglibrary ให้ใช้จำนวนหนึ่งด้วย
โดยมีพวก Data Grid กับ Tree ให้ใช้ด้วย
ลองดูตัวอย่างของ submit form
<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@ taglib uri="http://beehive.apache.org/netui/tags-databinding-1.0" prefix="ne
tui-data"%>
<%@ taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui"%>
<%@ taglib uri="http://beehive.apache.org/netui/tags-template-1.0" prefix="netui
-template"%>
<netui:html>
<head>
<title>User Register Page</title>
<netui:base/>
</head>
<netui:body>
<p>
Register Page
</p>
<netui:form action="processData">
Name: <netui:textBox dataSource="actionForm.name"/>
<br/>
Age: <netui:textBox dataSource="actionForm.age"/>
<br/>
Company: <netui:textBox dataSource="actionForm.company"/>
<netui:button type="submit" action="getCompany" value="Select Company"/>
<br/>
<netui:button type="submit" value="Submit"/>
</netui:form>
</netui:body>
</netui:html>


ใครที่สนใจเรื่อง architecture ถ้าเคยใช้ struts อยู่แล้ว
ก็น่าจะลองเข้าไปศึกษาดูว่า เขาออกแบบ extension อย่างไร

Related link from Roti

4 comments:

bact' said...

ยิ่งดูยิ่งปวดหัว
โชคดดีที่ผมไม่ต้องทำงานกับ framework พวกนี้ - -"

ทำไมจำนวนโค้ดมันเยอะขึ้น ๆ ทุกทีเนี่ย (นับที่ gen แล้ว) - -

นึกถึงเวลาผมไม่สบาย จะชอบฝันว่า ตัวเองขับรถสิบล้อคันใหญ่ ๆ บรรทุกของหนัก ๆ เต็มรถ แล้วรถมันก็วิ่งเร็ว ๆ อยู่ในเมือง ผมหยุดรถไม่ได้ ทำได้แต่เลี้ยวซ้ายขวา ต้องบังคับให้มันวิ่งไปตามทาง ไม่ให้ชน ... อาการแบบลนลาน ... แล้วก็ตื่น เหงื่อเต็มตัว


เกี่ยวกันมั๊ยเนี่ย - -

Anonymous said...

ใช่ คีนู รีฟ หรือเปล่าเนี่ย bact นะ :)

PPhetra said...

เขียน java นี่มันเยิ่นเย้อดีเนอะ
config เป็น xml ก็ตาลาย
เขียนเป็น annotaion ก็ตาลายอยู่ดี
นี่ถ้า bact ไปเห็น code ที่เขา implement ส่วน generate นะ
ตาลายกว่านี้เยอะเลย

bact' ถ้าตื่นแล้ว (จาก matrix)
อย่าลืมมาปลุกด้วยนะ

Anonymous said...

เพิ่งไปทำงานที่ใหม่ ให้ทำอันนี้ แรกๆก็ไม่ได้เขียน struts ปวดหัวไม่ใช่เล่นอยู่เหมือนกัน
ตอนนี้ ก็ยังหาข้อมูลอยู่เรื่อยๆ พอดีเจอเว็บที่มีภาษาไทยเว็บแรก เลยมา comment หน่อย 555