HOSxP

You are here: Home Support BMS Learning Center การ Patch Intraweb ให้ทำงานเป็น Page mode ได้จริงๆ
  • banner_bms_learning_center1.jpg
  • banner_bms_learning_center2.jpg

การ Patch Intraweb ให้ทำงานเป็น Page mode ได้จริงๆ

Intraweb เป็น web framework ใน delphi ที่ถูกออกแบบโดยใช้ concept what you see is what you get ที่มีมานานแล้ว concept นี้เป็นอะไรที่ถือว่า Advance มากๆ เมื่อหลายๆ ปี มาแล้ว (ตั้งแต่สมัย Delphi 7) และถึงตอนนี้ก็ยังคง Concept แบบนั้นอยู่

ปัญหาหลักๆ ของ Intraweb อยู่ที่ระบบภายในของมันเอง ซึ่งถูกออกแบบมาเพื่อนักพัฒนาที่ถนัดเขียนภาษา Delphi (Object Pascal) แต่จำเป็นต้องพัฒนา Web application แล้วไม่อยากไปใช้ php หรือ asp.net ถือว่ามี Learning curve ต่ำมากในการพัฒนา Web application โดย ตัว Intraweb component จะทำการ Render Component ที่ออกแบบไว้ใน IDE Form Designer ของ Delphi ให้กลายเป็น HTML+Java script เพื่อแสดงผลใน Web browser ได้ โดย Application ที่พัฒนาโดยใช้ Intraweb นั้น จะสามารถทำงานได้ในแบบที่เป็น Stand alone Web server (ผ่าน Indy http server) หรือ จะ compile ให้เป็น isapi แล้วไปใช้งานใน iis ก็ได้

 

ปัญหาของนักพัฒนาที่เมื่อใช้ Intraweb ใช้ไปสักระยะหนึ่งแล้วต้องเจอ ก็คือระบบการสื่อสารระหว่าง Web Browser และ Web Server ของ Intraweb นั้น จะทำได้โดยผ่าน Event ของ Component ใน Intraweb เท่านั้น ซึ่งปัญหานี้ค่อนข้างมีผลอย่างมากกับการพัฒนาโดยใช้ Web technology ใหม่ๆ อย่างเช่น JQuery ที่รองรับการเรียกใช้งาน ajax โดยที่ไม่ต้อง Refresh หน้าของ web page ได้

ถึงแม้ว่า Intraweb จะมีระบบรองรับการทำงานแบบ AJAX อยู่แล้ว แต่ระบบที่ว่านี้ ก็ต้องถูกเรียกใช้งานผ่าน Component ของ Intraweb เช่นเดียวกัน  เราลองมาดูว่าปัญหาตัวแรกของ Intraweb กันนะครับ

1. การ Submit form  การเกิด Event ของ Component ใน Intraweb นั้นจะเกิดในฝั่ง client (Web browser) แล้วส่ง active property ของ Component ทุกตัวกลับไปยัง Intraweb server ผ่านการ Submit form เพื่อที่ฝั่ง server จะได้ตรวจสอบได้ถูกว่าค่าต่างๆ ของ component แต่ละตัวมีสถานะเป็นอย่างไร ซึ่งปัญหาของการทำงานแบบนี้ก็คือ การเกิด Event แต่ละครั้ง จะมีการส่งข้อมูลเป็นจำนวนมากผ่านการ Submit Form ไปยัง Web browser เราจะเห็นปัญหานี้ชัดเจนหากใน Form นั้นๆ มี Component มากๆ จะใช้เวลามากเป็นพิเศษในการรอข้อมูลจาก web server

2. การสร้าง Hyperlink ไปยังหน้าอื่นๆ  ปัญหาแรกของนักพัฒนาที่ใช้ Intraweb ก็คือไม่สามารถสร้าง Hyperlink ไปยังหน้าอื่นๆ ได้โดยตรง เนื่องจากระบบของ Intraweb นั้น ในแต่ละหน้าที่ Web browser มองเห็นเกิดจากการสร้าง Form เอาไว้ที่ฝั่ง Web server และถูกออกแบบให้แสดงผลในหน้าที่ถูกสร้างเอาไว้แบบ Stack แล้วนำหน้าบนสุดของ Stack ส่งไปให้ Web Browser นักพัฒนาไม่สามารถใส่ Hyperlink ในรูปแบบของ <a href="/page2">Goto page 2</a> เอาไว้ในระบบของ Intraweb ได้  จะต้องสร้าง Event ให้กับ Component ของ Intraweb แล้วเรียกใช้ Method WebApplication.CreateForm(xxx) ของ Intraweb เพื่อสร้าง Form ส่งกลับไปให้ Web browser เท่านั้น

3. การสร้าง Back end support function บางครั้งเราต้องการสร้าง function ในฝั่ง web server ให้ส่งข้อมูลกลับมายัง Web browser ผ่าน AJAX โดยมี url /get_data?id=10 แต่ในระบบของ Intraweb นั้นมันทำได้ยากเหลือเกิน เพราะต้องไปเขียนเอาไว้ใน Event onBeforeDispatch ของ ServerController

ปัญหาแค่ 3 ข้อนี้ บางครั้งก็ทำให้นักพัฒนาเบื่อกับ Intraweb ได้เหมือนกันครับ ถ้าปัญหาใหญ่ๆ 3 ข้อนี้ถูกแก้ไขได้ มันก็จะทำให้ Intraweb น่าใช้งานมากขึ้นอีกหลายเท่าตัวเลยที่เดียว  หลังจากที่ผมได้ใช้ Intraweb ในหลายๆ โครงการผมก็ได้เจาะลึกเข้าไปในระบบของ Intraweb ขึ้นเรื่อยๆ จนกระทั้งซื้อ Support Service ที่เรียกว่า Ultimate package จาก Atozed เพื่อเข้าถึง Source code ของ Intraweb ได้

สุดท้าย ผมก็หาวิธีที่จะแก้ไขปัญหา 3 ข้อนี้ได้ ถึงแม้ว่ามันจะไม่ใช่แบบที่ดีที่สุด แต่มันก็ใช้ได้ครับ

คราวนี้เรามาลองดูว่าจะแก้ปัญหาแต่ละข้อได้อย่างไร เราจะใช้วิธีไหนในการแก้ปัญหานี้ดี จริงๆ แล้วการแก้ปัญหานี้จะทำได้ก็ต้องเข้าไปแก้ไข Source code ของ Intraweb แต่หากไม่มี Source code ของ Intraweb ล่ะ จะทำอย่างไรดี  วิธีการที่ผมคิดออกก็มีหลายวิธีครับ ตั้งแต่การเขียน Class helper ไปจนถึงการ Patch code ของ Intraweb ในระบบ compile ของ delphi นั้น เราสามารถเขียน method ไปทับ class ไหนๆ ก็ได้ ซึ่งเรียกว่า Code redirect เป็นการสร้าง method ขึ้นมาใหม่แล้วกำหนดให้ method pointer ตัวเก่าชี้มาใช้งานที่ตัวใหม่ครับ วิธีการนี้ทำให้เราสามารถแก้ไขบางส่วนของ Code ใน Unit ที่ถูก Compile ไปแล้วโดยไม่ต้องทำการ Compile unit นั้นใหม่ ซึ่งจะมีประโยชน์อย่างมากในกรณีที่เราไม่มี Source code ของ unit เก่า แต่จำเป็นต้องแก้ไข code บางส่วน  ตัวอย่างของระบบที่ทำงานแบบนี้ก็ได้แก่ FastCode project หรือ FastMM project ครับที่ได้ทำการสร้าง method ที่ทำงานได้เร็วกว่าเดิมไปแทนที่ของเก่าที่อยู่ใน rtl ของ delphi

การสร้าง Code redirect ที่จะไปแทนที่ method ใดๆ ได้นั้น จำเป็นที่จะต้องทราบ Source code ของ method นั้นๆ ด้วยครับ ซึ่งในกรณีของ Intraweb โชคดีที่ผมเข้าถึงได้ผ่าน Ultimate support channel สิ่งที่ผมต้องเข้าไปแก้นั้นมีหลายจุดครับ ซึ่งเป้าหมายก็คือเปลี่ยนวิธีการทำงานของ Intraweb บางส่วนให้รองรับการเข้าถึงหน้า (Form) ได้จาก URL โดยไม่ต้องผ่าน Event ของ Component ใน Form ครับ โดยผมต้องการให้แสดง Form2 ได้จาก URL คล้ายๆ แบบนี้ http://server-ip:8888/showform?name=Form2  และหากใน Form2 มี property ที่สามารถรับค่าได้ผมก็อาจจะส่งค่าไปกับ URL ด้วยเลยดังนี้ http://server-ip:8888/shorform?name=Form2&KeyID=10 ซึ่งวิธีการนี้แทบจะเป็นไปไม่ได้เลยหากใช้ Delphi 7 ลงไป แต่โชคดีที่ตั้งแต่ Delphi 2010 เป็นต้นมาได้มีการพัฒนาระบบ RTTI ใหม่ และเราก็จะใช้ระบบ RTTI นี้เข้ามาช่วยให้การทำงานแบบนี้เป็นจริงขึ้นมาได้ครับ

ก่อนจะไปที่ RTTI เรามาดูวิธีการเขียน Code redirect กันก่อนนะครับว่าจะเขียนได้อย่างไร อันดับแรกจะต้องใช้  Unit ที่ทำหน้าที่ในการ Redirect code ครับ Download ได้จากที่นี่ครับ <CodeRedirect.pas> ส่วนวิธีการเขียน Code Redirect นั้นง่ายมากครับ โดยเราต้องทำการประกาศ Class ขึ้นมาใหม่ก่อนสักตัวหนึ่งที่มี การประกาศ Function ให้เหมือนกับ Class ที่เราต้องการ patch จากนั้นก็ทำการ patch ในส่วน Initialization ของ unit ครับ ตัวอย่างดังนี้ครับ

สมมุติว่าผมอยากจะแก้ไขระบบ Generate Session ID ของ Intraweb ที่เป็นรหัสแบบสุ่ม ให้เป็นวันที่และเวลา+ID สุ่ม แทน ผมก็ต้องเขียน Patch แบบนี้ครับ

[Example Code 1]

ส่วน Code ทั้งหมดที่ต้องเข้าไปแก้ มีอยู่ 3 จุด ได้แก่

[Example Code 2]

[Example Code 3]

[Example Code 4]

 

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

 

 

<to be continued>