Friday, January 11, 2008

Qi4j

Qi4j ออกเสียงว่า "chee for jay"
ความพยายามใหม่ของ Rickard Öberg (co-founder of JBoss)
ที่ตั้งชื่อว่า "Composite Oriented Programming"
โดยมีฐานต่อยอดจาก Java
Qi4j is a framework for domain centric application development, including evolved concepts from AOP, DI and DDD.


แนวคิดหลักๆคือ
1. fine-grained parts, แยกส่วน model ออกเป็นหลาย part เช่น behavior part กับ state part
แล้วเวลาใช้ ค่อยนำมาประกอบกันในลักษณะของ Composite
การแยกส่วนแบบนี้เชื่อว่า จะนำมาสู่การ reuse ที่ดียิ่งขึ้น
2. Context-base behavior, composite เดียวกัน แต่ถ้าอยู่ใน context ที่ต่างกัน
ก็จะมี behavior ที่ต่างกันได้

ลองดูเฉพาะข้อ 1 กันก่อน
ถ้าใครคุ้นกับ ruby, พออ่านข้อ 1 แล้วอาจจะนึกถึง Mixin
ลองเปรียบเทียบกับตัวอย่างใน tutorial ที่ว่าด้วย HelloWorld ของ Qi4j ดู

ปกติ HelloWorld model ถ้าเขียนแบบปกติ ก็เขียนได้ดังนี้
public class HelloWorld {
String name;

public String say() {
return "hello " + getName();
}

public void setName(String name) {
this.name = name;
}

public void getName() {
return name;
}
}

ถ้าเราแยก HelloWorld ออกเป็นส่วนๆ เราจะเห็นว่า มันประกอบด้วย
behavior part ซึ่งก็คือ method say
กับ state part ซึ่งก็คือ property name

เขียนแบบ Qi4j ก็จะต้องทำดังนี้
(ใน Qi4j เขามี concept ว่า "Classes ard dead, Long live interfaces.")

เริ่มด้วย declare model เราด้วย interface
public interface HelloWorld
extends HelloWorldBehaviour, HelloWorldState
{
}

@Mixins( HelloWorldStateMixin.class )
public interface HelloWorldState
{
Property<String> name();
}

@Mixins( HelloWorldBehaviourMixin.class )
public interface HelloWorldBehaviour
{
String say();
}

implement logic ของ behavior
public class HelloWorldBehaviourMixin
implements HelloWorldBehaviour
{
@ThisCompositeAs HelloWorldState state;

public String say()
{
return state.phrase() + " " + state.name();
}
}

implement logic ของ state
public class HelloWorldStateMixin
implements HelloWorldState
{
@PropertyField Property<String> name;

public Property<String> name()
{
return name;
}
}

สุดท้ายประกอบทั้งหมดเข้าหากัน
public interface HelloWorldComposite
extends HelloWorld, Composite
{
}


ลองเปรียบเทียบกับการเขียน Mixin ด้วย ruby ดูบ้าง
module HelloState
attr_accessor :name
end

module HelloBehavior
def say
puts "hello #{@name}"
end
end

class HelloWorld
include HelloState
include HelloBehavior
end


ตอนนี้ tutorial ในส่วน context base behavior ยังไม่ออกมา
ก็ต้องรอดูกันต่อไป ว่าจะออกมาหน้าตาเป็นอย่างไร

Related link from Roti

Thursday, January 10, 2008

ปวดหัวกับ PXE

ช่วงนี้ผมกำลัง config พวก Network boot ด้วย PXE
แล้วก็เจอปัญหาที่ว่า เครื่องรุ่นใหม่ๆ สามารถ boot ได้ตามปกติ
แต่เครื่องรุ่นเก่ากลับเจอ error ฟ้องว่า
PXE-E53 No boot filename received

ท้าวความก่อนว่า เจา PXE protocol นี่มันจะอาศัย DHCP protocol เป็นพาหนะ
เนื่องด้วย DHCP protocol เขาออกแบบไว้ดี, มันออกแบบให้มี slot options เผื่อไว้
เจ้า PXE protocol ก็เลยอาศัย options นี่แหล่ะเป็นช่องทางไว้สื่อสาร

สำนึกแรกผม เมื่อเห็นคำว่า "No boot filename received"
ก็ต้องหมายความว่า DHCP server ไม่ได้ส่ง option นี้กลับมา
แต่ถ้ามันไม่ได้ส่งกลับมาแล้ว ทำไม เครื่องรุ่นใหม่ๆ boot ได้หล่ะ
หรือว่า config DHCP server ไม่ถูกหว่า ทำให้มันส่งกลับมาไม่ถูก
ก็เลยหมกมุ่นแต่กับการแก้ configuration ของ DHCP
ซึ่งไม่ว่าจะแก้อย่างไร ก็ไม่มีความคืบหน้าใดๆให้เห็น

หลังจากพายเรือวนในอ่างมาหลายวัน
สุดท้ายก็ต้องใช้อาวุธลับ นั่นก็คือ wireshark + tcpdump เข้ามาช่วย debug
(โดยมีพี่สมภพเป็นคนช่วยแกะ packet)
ได้ความว่า

ในเครื่องใหม่ๆ protocol ของ PXE (เฉพาะครึ่งแรก ตอนที่ solve หา bootfile name กับ tftp server)
จะเป็นดังนี้


  • client broadcast จาก port 68 ไปยัง port 67 อันนี้เรียกว่า DHCP Discover
  • server broadcast กลับมา พร้อมค่า configuration ต่างๆ อันนี้เรียกว่า DHCP Offer
  • client broadcast ไปอีก โดยส่งค่า configuration ที่ได้จากขั้น 2 ไปด้วย ขั้นนี้เรียก DHCP Request
  • server broadcast ยืนยันรับทราบกลับมา ขั้นนี้เรียกว่า DHCP ACK

หลังจาก 4 step นี้แล้ว เจ้า PXE client ก็จะเข้าสู่ขบวนการ download file จาก tftp server

แต่ในเครื่องเก่าๆ protocol ของ PXE มันเป็นแบบนี้
เริ่มด้วย 4 อันแรกนี่เหมือนปกติ ทุกอย่าง แต่มันเพิ่มมาอีก 1 อันคือ


  • client ส่ง DHCP Request ไปที่ server ซำ้อีกครั้ง
    แต่สิ่งที่แตกต่างจากขั้นแรก ก็คือ
    • การส่งไม่ได้ใช้กลไก broadcast เหมือนครั้งแรก (เนื่องจากมันได้เบอร์ IP ของตัวเองมาแล้ว)
    • port ที่ request ไป กลายเป็น port 4011



เมื่อ check ที่ server ก็พบว่า ที่ port 4011 นั้น ยังไม่มี process start อยู่เลย
ความคิดแรกสุด ก็คือ เราทำ port forwarding จาก port 4011 ส่งไป 67 ดีไหม
หรือ จะติดตั้ง PXE daemon ซึ่งปกติเป็นคนรับผิดชอบเจ้า port นี้อยู่

สุดท้ายเลือกทางง่าย ก็คือลง PXE daemon ไปก่อน (เพราะทำ forward ไม่เป็น)

Related link from Roti