Friday, November 24, 2006

CForms

CForms คือ framework ย่อยๆใน Apache Cocoon
ที่ออกแบบมาเพื่อใช้จัดการเรื่องการ submit ข้อมูลผ่าน html form

CForms มีองค์ประกอบ 2 ส่วนคือ
  • Form Model คือ definition ของ data ที่จะ submit เข้ามา
  • Form Template คือ layout ของ widget
    ที่จะสร้างเป็นหน้าจอให้ผู้ใช้เห็น

แน่นอนว่าด้วยชื่อเสียงของ Cocoon ที่เป็น Framework แห่ง xml
ทั้ง form model และ template ก็ต้อง describe ด้วย xml

สำหรับตัว Form model สิ่งที่ผมชอบก็คือ
เรากำหนด definition ของ form ผ่านทาง xml อย่างเดียว
ไม่จำเป็นต้องไปเขียน java class ใดๆเลย
ลองดูตัวอย่าง form model
<fd:form
xmlns:fd="http://apache.org/cocoon/forms/1.0#definition">

<fd:widgets>
<fd:field id="name" required="true">
<fd:label>Name:</fd:label>
<fd:datatype base="string"/>
<fd:validation>
<fd:length min="2"/>
</fd:validation>
</fd:field>

<fd:field id="email" required="true">
<fd:label>Email address:</fd:label>
<fd:datatype base="string"/>
<fd:validation>
<fd:email/>
</fd:validation>
</fd:field>

</fd:widgets>
</fd:form>

จะเห็นว่าใน form หนึ่งๆ ประกอบด้วย widget หลายๆอัน
ในตัวอย่างของเราชนิดของ widget ที่ใช้ก็คือ Field widget
โดยแต่ละ field ก็จะมีการกำหนด label, datatype, validation
(CForms provide build-in widget มาให้พอสมควร
และเปิดช่องให้เรา define custom widget เข้าไปได้)

ส่วนหน้าตาของ form template ก็จะมีหน้าตาแบบนี้
<html xmlns:ft="http://apache.org/cocoon/forms/1.0#template"
xmlns:fi="http://apache.org/cocoon/forms/1.0#instance"
xmlns:jx="http://apache.org/cocoon/templates/jx/1.0">

<jx:import uri="resource://org/apache/cocoon/forms/generation/jx-macros.xml"/>

<head>
<title>Registration form</title>
</head>
<body>
<h1>Registration</h1>
<ft:form-template action="#{$continuation/id}.continue" method="POST">
<ft:widget-label id="name"/>
<ft:widget id="name"/>
<br/>
<ft:widget-label id="email"/>
<ft:widget id="email"/>

<input type="submit"/>
</ft:form-template>
</body>
</html>

จะเห็นว่ามีการ map widget เข้ากับบริเวณต่างๆใน template
เมื่อมีการ render page นี้, component ย่อยแต่ละตัว ก็จะรับผิดชอบ render ตัวเอง
แล้วนำผลลัพท์ที่ได้มาแทนที่ลงไป

และเมื่อ form ถูก submit กลับเข้ามา,
CForms ก็จะแจกให้ component แต่ละตัว
รับผิดชอบในการดึงข้อมูลออกจาก HttpRequest
และนำข้อมูลท่ี่ได้ไปใส่ไว้ใน form instance

เวลาจะนำ CForm ไปใช้ เรามักจะใช้ผ่าน flowscript
ลองดูตัวอย่าง
cocoon.load("resource://org/apache/cocoon/forms/flow/javascript/Form.js");

function registration() {
var form = new Form("registration_definition.xml");

form.showForm("registration-display-pipeline");

var viewData = { "username" : form.getChild("name").getValue() }
cocoon.sendPage("registration-success-pipeline", viewData);
}

โปรแกรมตัวอย่างนี้ จะแสดงหน้าจอให้ user กรอก และเมื่อ user submit เข้ามา
ก็จะทำการแสดงหน้า success
จุดเด่นของ flowscript ก็คือ
1. ใช้ syntax javascript ซึ่ง implement ได้เร็วกว่า java code
2. implement โดยใช้ continuation ทำให้เขียน code อยู่เป็นกลุ่มก้อน ง่ายต่อการ maintain
framework ปัจจุบันที่ใช้ continuation style แบบนี้ ก็คือ Seaside ที่ใช้ภาษา smalltalk,
แล้วก็ web framework ของ DrScheme ที่เขียนด้วยภาษา scheme,
ส่วนในค่าย java นี้ก็มีแค่ cocoon ตัวเดียว
(่jetty continuations เป็นอีกเรื่องหนึ่ง ที่ใช้ศัทพ์เดียวกัน แต่คนละ concept)

ในโปรแกรมข้างบน จุดที่เกิด continuation ก็คือ method form.showForm
ซึ่ง cocoon จะทำการ pause execution ไว้ก่อน
เมื่อ user submit เข้ามา จึงจะเริ่มทำงานต่อจากจุดเดิม

ทั้งหมดข้างบน เป็นแค่ demo การใช้ง่านง่ายๆ
แต่เวลานำไปใช้จริงๆ ข้อมูลนำมาใช้บน form
มักจะอยู่ในรูป xml หรือ beans
ดังนั้นจึงต้องมีขบวนการ binding เกิดขึ้นด้วย
CForms ใช้ XPath เข้ามาช่วยในการ binding
ลองดูตัวอย่าง
<fb:context xmlns:fb="http://apache.org/cocoon/forms/1.0#binding" path="/" >
<fb:value id="name" path="name"/>
<fb:value id="email" path="email"/>
</fb:context>

attribute path ข้างบน ก็คือ xpath ที่ชี้ไปยัง xml element ที่ต้องการ bind

ส่วนประเด็นสมัยนิยม ก็คือเรื่อง Ajax
ตัว CForms ใช้หลักการ partial renderer
ดังนั้นในตอนที่เราเขียน template ก็ต้องใช้พวก tag พวก div, span
เข้ามา grouping บริเวณที่จะเกิดการ replace
ส่วนการ handler request
เนื่องจาก cocoon เป็นเจ้าพ่อแห่ง pipeline
ดังนั้นเราก็แค่แทรก tranformer กับ selector ที่ใช้ handle ajax
เข้าไปใน sitemap

เท่าที่ดูมา CForms ก็ดูเข้าท่าดีเหมือนกัน
ประเด็นที่ต่างกับพวก Tapestry หรือ JSF ก็คือ
  • ใน Tapestry form จะปนๆอยู่กับ controller
    แต่ใน CForms, Forms จะแยกออกจาก controller อย่างชัดเจน
    (seperation of concern จะดีกว่า)
  • ใน JSF เวลาจะเลือกประเภทการ render เราทำได้โดยเปลี่ยน RenderKit
    ใน CForms เนื่องจากเราใช้ concept ของการ transform
    ดังนั้นการเปลี่ยนการ render ก็คือการเปลี่ยน XLST
    ส่วนใน Tapestry ไม่มี concept แบบนี้
  • สามารถใช้ได้โดยไม่ต้องรู้ java เลย


ส่วนข้อเสียที่เห็นได้ชัดก็คือ XML เยอะจริงๆ

Related link from Roti

Thursday, November 23, 2006

Eclipse JDT, ASTParser

ปัจจัยหนึ่งที่ทำให้ Eclipse ได้เปรียบ netbeans (หมายถึง netbeans ตัวเก่าๆนะ ตัวใหม่นี่ยังไม่มีข้อมูล)
ก็คือตัว Java Parser
ซึ่ง bundle อยู่ใน package eclipse JDT (java development tools)

เมื่อใดก็ตามที่เราเปิด source code ขึ้นมาใน editor
eclipse จะใช้ ASTParser ทำการ parse source code
ไปเป็น AST (Abstract Syntax Tree)
ข้อมูล AST ที่ได้จะถูกนำไปใช้หลายๆที่ เช่นใช้ใน Outline view
แต่ที่หนึ่งที่สำคัญก็คือ มันใช้เป็นข้อมูลสำหรับการทำ Refactoring

ลองดู code ตัวอย่างนี้
สมมติเรามี

int x;
x = 2 * 3;

ถ้าเราต้องการ refactor ยุบให้เหลือแค่นี้
int x = 2 * 3;


ผมจะลองเขียน code ให้ดูว่า ถ้าใช้ Eclipse JDT api
เข้ามายุบ source code ข้างบนนั้น
เราจะต้องเขียนอย่างไรบ้าง
เริ่มด้วยการ parse java code ก่อน

ASTParser parser = ASTParser.newParser(AST.JLS3);
parser.setKind(ASTParser.K_STATEMENTS);
String src = "int x; x= 2 * 3;";
parser.setSource(src.toCharArray());
ASTNode node = parser.createAST(null);

AST.JLS3 คือ version ของ java code ที่เราจะ parse
ตัว ASTParser มี choice ให้เลือกอยู่แค่ 2 ตัวคือ JLS3 กับ JLS2
ตัว JLS3 จะ support syntax ของ Java 1.5

ขั้นถัดไปก็คือทำการหาว่า จุดไหนที่ทำ refactor ได้บ้าง
โดยเราจะค้นหา statement ที่เป็น variable declaration
กับ statement ที่เป็น assignment
การค้นหานี้ เราจะใช้ visitor pattern ในการค้นหา
(Note: เขียนแบบสั้นๆ พอให้ทำงานได้ ไม่เช็คเงื่อนไขใดๆทั้งสิ้น)

final ArrayList list = new ArrayList();
final HashMap map = new HashMap();

node.accept(new ASTVisitor() {
@SuppressWarnings("unchecked")
public boolean visit(VariableDeclarationStatement node) {
list.add(node);
return false;
}

public boolean visit(Assignment assignment) {
Expression left = assignment.getLeftHandSide();
map.put(left.toString(), assignment);
return false;
}
});

ขั้นสุดท้ายก็คือการแก้ไข AST ให้ตรงตามที่เราต้องการ
// loop ไปตาม declaration statement ที่หามาได้
for (Iterator iter = list.iterator(); iter.hasNext();) {

VariableDeclarationStatement stmt = (VariableDeclarationStatement) iter.next();
// เนื่องจาก declarable statement หนึ่งๆ
// มีได้หลายตัวแปรพร้อมๆกัน
// ดังนั้นเราต้อง loop ไปตามตัวแปรแต่ละตัวอีกที
List fragment = stmt.fragments();
for (Iterator iterator = fragment.iterator(); iterator.hasNext();) {
VariableDeclarationFragment f = (VariableDeclarationFragment) iterator.next();
//ทำเฉพาะ case ที่ตัวแปรไม่ได้มีการ initlize ไว้
if (f.getInitializer() == null) {
// ค้นหา assigment ที่มีตัวแปรเดียวกัน
Assignment assignment = (Assignment) map.get(f.getName().toString());
Expression right = assignment.getRightHandSide();
f.setInitializer(copyExpression(right));
assignment.getParent().delete();
}
}
}

จะเห็นว่า เราแค่ copy right hand side ของ Assignment statement
มาใส่ตรง Initialize value ของ Variable declaration Statement
จากนั้นก็ลบ assignment statement ทิ้งเสีย

สนใจรายละเอียด
ลองตามไปอ่าน Tutorial ของ Eclipse ที่ชื่อ Abstract Syntax Tree

Related link from Roti

Wednesday, November 22, 2006

F3

ห่างเหินจาก Swing มานาน
เลยพึ่งได้ยินข่าว F3
F3 ย่อจาก "Form Follows Function".
เป็น project ของ Chris Oliver
โดยเขา design declarative script language
สำหรับการสร้าง gui ขึ้นมา
จุดเด่นของมันก็คือ มัน support ทั้ง Swing และ Java2D

ลองดูตัวอย่าง ที่ผม copy มาจาก tutorial ของเขา
Frame {
title: "Hello World F3"
width: 200
content: Label {
text: "Hello World"
}
visible: true
}



จะเห็นว่า ภาษามีลักษณะคล้ายๆ javascript

ที่นี้ลองแบบมี model + binding ด้วย
class HelloWorldModel {
attribute saying: String;
}

var model = HelloWorldModel {
saying: "Hello World"
};

var win = Frame {
title: "Hello World F3"
width: 200
content: Label {
text: bind model.saying
}
visible: true
};



ลองดูลูกผสมระหว่าง 2D กับ Swing

Canvas {
content: Group {
transform: []
content:
[Rect {
x: 20
y: 20
height: 80
width: 300
arcHeight: 20
arcWidth: 20
fill: cyan
stroke: purple
strokeWidth: 2
},
Ellipse {
cx: 150
cy: 80
radiusX: 100
radiusY: 50
fill: orange
stroke: blue
strokeWidth: 2
},
View {
transform: translate(150, 70)
content: Button {
cursor: DEFAULT
text: "Click Me!"
}
},
Polygon {
points: [5, 5, 25, 5, 15, 25]
fill: gray
stroke: black
strokeWidth: 3
},
View {
transform: translate(100, 40)
content: TextField {
columns: 15
value: "This is a text field"
}
}]
}
}



ที่น่าสนใจก็คือ มันเป็น graphic ที่สามารถ transform ได้ด้วย
ทำให้เราทำ swing เอียงๆ แบบนี้ แล้วยังสามารถป้อนข้อมูลได้ด้วย

Related link from Roti

Tuesday, November 21, 2006

Saori

Saori ไม่ใช่ชื่อสาวญี่ปุ่น
แต่เป็นชื่อกรรมวิธีทอผ้าด้วยมือแบบหนึ่ง
ถ้าลองใช้ google ค้นหาคำนี้จากเฉพาะ site ในประเทศไทย
จะเห็นว่ามีอยู่ที่หนึ่งที่เกี่ยวข้องกับ ซึนามิ
นั่นคือโครงการ saori for tsunami thailand
ที่จัดตั้งโดย มูลนิธิมายา โคตมี



ใครเจอป้ายแบบนี้ ก็อุดหนุนเขาได้เลยครับ

จุดเด่นของเครื่องทอผ้าของ saori คือความง่ายในการใช้
เนื่องจากออกแบบมาโดยคำนึงถึงผู้พิการด้วย

ใน site www.saoriworcester.com เขาแปลหลักการ 4 ข้อ
"The way of saori" ไว้ดังนี้
1. Consider the differences between machines and people
ชอบตัวอย่างที่เขาพูดถึง
ปัจจุบันเรามีแนวโน้มจะมองทุกอย่างในแง่จักรกลมากขึ้น
เช่น ใช้ศัทพ์ว่า "human resources" แทนที่จะเรียกว่า "human beings"
2. Let's adventure beyond our imagination (Explore with all your might).
อย่างที่รู้กัน การทำงานสร้างสรรค์ ช่วยให้เราค้นพบ ธรรมชาติที่ซ่อนอยู่ในตัวตนของเรา
3. Let's look out through eyes that shine
อันนี้สิที่ผมชอบ ตรงกับที่ผมเคยเขียนในเรื่อง "อันเนื่องจากการเดิน"
ด้วย "eyes that shine" จะทำให้เราค้นพบ
สิ่งมหัศจรรย์เล็กๆน้อยๆรอบตัวเรา
ไม่ว่าจะเป็นลวดลายแตกร้าวของอิฐ, ดอกหญ้าเล็กๆข้างกำแพง
4. Let's learn from everyone in the group
friendships, friendships, friendships...
กิจกรรมที่ไม่เลือกชนชั้นอย่างนี้ เป็นสะพานเชื่อมความสัมพันธ์
ระหว่างคนต่างที่มาได้เป็นอย่างดี

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

ทอผ้ามันมีเสน่ห์ดี
สำหรับคนเมืองอย่างเรา การได้ใส่เสื้อที่ทำกับมือ
มันน่าจะให้ความรู้สึกที่ดีมากนะ



ภาพจาก Photogallery ของ saoriworcester.com

Related link from Roti