Saturday, May 21, 2005

Song Search By Tapping

เป็น project ที่ทดลองค้นหาเพลงโดย
ใช้การเคาะจังหวะเป็นข้อมูล input
ผมทดลองแล้ว 4 เพลง ตรงเพี๊ยะเสีย 2 เพลง
ที่ค้นได้ก็มี 10 little indian กับ twinkle little start
ส่วน happy birth day เคาะยังไงก็หาไม่เจอ
ลองได้ที่นี่ครับ link

Related link from Roti

SiteMesh

หลังจากลองไล่ดู code ที่ AppFuse generate ให้
ก็พบว่ามีการนำ SiteMesh มาใช้
เจ้า sitemesh ก็คือ decoration framework (ทำหน้าที่เหมือน Tiles ใน Struts)
ทำหน้าที่ intercept response จาก web application
แล้วทำการ extract เฉพาะส่วน body, head
เพื่อนำไปแสดงบน template ที่ได้เตรียมไว้
อธิบายยากแท้ ดูรูปเอาแล้วกัน



เท่าที่อ่านดู feature หรือ การใช้งาน
ก็ดูดี คงต้องทดลองใช้งานก่อน
จึงจะรู้ว่าดีกว่า Tiles หรือเปล่า
แต่เท่าที่จำได้เวลาใช้ tiles จะน่าเบื่อ
ตอนเขียน xml definition ของ tiles
ซึ่งซ้ำไปซ้ำมา และมี Naming ของ page
เกิดขึ้นอีก 1 กลุ่ม (ต้องตั้งชื่อให้กับ
ผลลัพท์ของการจับคู่ template กับ content)

feature ของ sitemesh
  • Determine decorator based on path of requested page.
  • Use different decorators based on time, locale or browser.
  • Use simplified decorators for search-engine robots.
  • Switch decorators based on a URL parameter, request attribute or meta-tag.
  • Use custom decorators based on user's saved settings...


ในการ config ใช้ sitemesh ก็เพียงแต่ใส่ filter, filter-mapping เข้าไปใน web.xml
<filter>
<filter-name>sitemesh</filter-name>
<filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
</filter>

<filter-mapping>
<filter-name>sitemesh</filter-name>
<url-pattern>/*</url-pattern>
<!-- These are needed by Tomcat 5 for forwards -->
<!--dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher-->
</filter-mapping>


เริ่มแรกก็สร้าง file sitemesh.xml ไว้ใต้ WEB-INF
parser tag เป็นตัวกำหนดว่าจะใช้ parser ตัวไหนสำหรับ content แต่ละแบบ
แต่เจ้า sitemesh ให้มาเฉพาะ html parser เท่านั้น
ส่วน decorator-mapper เป็นตัวกำหนด
ว่าจะใช้ decorator อะไรสำหรับเงื่อนไขแบบไหน
ในกรณีนี้เป็นการใช้ ConfigDecoratorMapper
ซึ่งจะอ้างถึง config file ที่ชื่อ decorators.xml อีกที
<sitemesh>
<property name="decorators-file" value="/WEB-INF/decorators.xml"/>
<excludes file="${decorators-file}"/>
<page-parsers>
<parser default="true" class="com.opensymphony.module.sitemesh.parser.HTMLPageParser"/>
<parser content-type="text/html" class="com.opensymphony.module.sitemesh.parser.HTMLPageParser"/>
<parser content-type="text/html;charset=ISO-8859-1" class="com.opensymphony.module.sitemesh.parser.HTMLPageParser"/>
</page-parsers>

<decorator-mappers>
<mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
<param name="config" value="${decorators-file}"/>
</mapper>
</decorator-mappers>
</sitemesh>

ในเนื้อหาของ file decorators.xml
เราสามารถกำหนดได้ว่า จะให้ exclude อะไร
แล้วก็กำหนด pattern ว่า pattern อะไร
ใช้ jsp ตัวไหนเป็น template

<decorators defaultdir="/decorators">
<excludes>
<pattern>/demos/*</pattern>
<pattern>/resources/*</pattern>
</excludes>
<decorator name="default" page="default.jsp">
<pattern>/*</pattern>
</decorator>
</decorators>


สุดท้ายก็เป็นตัวอย่างของ template
ซึ่งใช้ taglib decorator:head กับ decorator:body
เป็นตัวกำหนดจุดที่จะนำเนื้อหามา insert

<%@ taglib
uri="http://www.opensymphony.com/sitemesh/decorator"
prefix="decorator" %>
<html>
<head>
<title>
My Site -
<decorator:title default="Welcome!" />
</title>
<decorator:head />
</head>
<body>
<table>
<tr>
<td>
<H1>
SiteMesh Corporation
<H1>
</td>
</tr>
<tr>
<td><decorator:body /></td>
</tr>
<tr>
<td> SiteMesh copyright</td>
</tr>
</table>
</body>
</html>


ข้อมูลเพิ่มเติม

Related link from Roti

Thursday, May 19, 2005

Eclipse 3.0 stat

มีใตรเคยเห็น stat นี้หรือยังครับ
ตัวที่ผมชอบก็มี

Automated JUnit tests run every build: 21,332

Wow เยี่ยม เคยทำ test แค่หลัก 20-100


Donuts consumed (North American committers): 1,120
Cigarettes inhaled (European committers): 14,656

ของเราอาจจะใช้จำนวนซองมาม่า แทน


Most CVS revisions for one file (JavaCore.java): 413

เคยทำไว้ได้สูงเหมือนกัน แต่จำตัวเลขไม่ได้
แต่เป็นเพราะออกแบบผิด
ทำเป็น build script เดียว แทน
ที่จะแยกไปตาม subproject
ทุกคนเลยรุมแก้ที่จุดเดียว


Lines of Java source code: 1,903,219

โปรเจคที่แล้ว 4 เดือนครึ่ง 200,000 กว่าบรรทัด
เทียบกันไม่ติด

Related link from Roti

Dumbster - Email Testing

ในการเขียน Application ในยุค Internet นี้
ส่วนใหญ่เรามักจะออกแบบให้มี feature
Mail Alert ซึ่งเป็นการแจ้งเตือนผู้ใช้
ถ้าเกิดเหตุการณ์อะไรบางอย่าง
สมัยก่อนเวลาผม implement feature นี้
แล้วเกิดต้องการจะ test
ก็เพียงแต่ set config ให้ mail ไปหา
account ตัวเอง แล้วก็ทดลองจำลอง
เหตุการณ์ จากนั้นก็เข้าไป check mail
ตัวเองว่ามีการส่ง mail มาจริงหรือเปล่า

มี solution อีกอันที่ผมพบใน AppFuse
ก็คือใช้ Dumbster ซึ่งเป็น Fake SMTP Server
ร่วมกับ junit ในการ test

ตัวอย่างการเขียน testcase
public void testExecute() throws Exception {
request.addParameter("username", "tomcat");
page.setRequestCycle(getCycle(request, response));
SimpleSmtpServer server = SimpleSmtpServer.start(2525);

page.execute(page.getRequestCycle());

assertFalse(page.hasErrors());

// verify an account information e-mail was sent
server.stop();
assertTrue(server.getReceivedEmailSize() == 1);

// verify that success messages are in the request
assertNotNull(page.getSession().getAttribute("message"));
}


กรณีที่ test แบบนี้ เราจะเรียตัว dumbster ว่าเป็น
Mock Object (จริงๆอาจจะเรียกได้ไม่เต็มปากนัก
แต่ลักษณะ pattern เป็นไปตามนั้น)
สำหรับใครที่ยังไม่คุ้นกับการ
test แบบนี้ ลองอ่านเรื่อง Mock object ที่ link นี้ครับ
What Are Mock Objects?
MockObjects

ไว้คราวหน้าจะแสดงให้ดูว่า Tapestry
มีวิธีการใช้ MockObjects ในการ test อย่างไร
(ได้ตัวอย่างมาจาก AppFuse อีกเช่นกัน)

Related link from Roti

Wednesday, May 18, 2005

Rounded, shaded corner box with minimum div tag

ปกติเวลาเราทำ rounded box ด้วย css จะพบว่า
ตัว content ที่เราใช้ถึงแม้จะเอาส่วน presentation ออกไปแล้ว
ก็ยังอุดมไปด้วย div block อยู่ดี (แถมยังไม่ค่อยสื่อความหมายเท่าไรด้วย)
ตัวอย่าง
<div class="cb">
<div class="bt"><div></div></div>
<div class="i1">
<div class="i2">
<h1>title go here</h1>
<p>xxxxx</p>
</div>
<div class="bb"><div></div></div>
</div>


มีอีก idea หนึ่งก็คือเปลี่ยนไปใช้ javascript
ให้เป็นคน insert tag พวกนี้แทน
จากตัวอย่างข้างบน ก็จะลดรูปเหลือแค่
<div class="cbb">
<h1>title go here</h1>
<p>xxxx</p>
</div>

จากนั้นเมื่อเวลาที่ browser load ไป
ตัว javascript ก็จะจัดการแทรก div tag
เพิ่มเติมให้เรา

อย่างนี้สิ ค่อยดู simple หน่อย (เฉพาะใน
content)

ดูบทความที่พูดถึงเรื่องนี้ที่
Transparent custom corners and borders

Related link from Roti

Tuesday, May 17, 2005

DBUnit

ต่อจากเมื่อวานที่ได้ทดลองใช้ AppFuse ไป
จากการอ่าน tutorial ทำให้รู้ว่า AppFuse ใช้
DBUnit เป็นตัว setup database สำหรับ
การ run testcase

สมัยก่อนผมใช้ ant task ที่ชื่อ <sql>
ในการ setup database ก่อนที่จะทำ
test case โดยใช้ผ่าน ant ดังนี้
<sql
driver="org.postgresql.Driver"
url="jdbc:postgresql://${test.host.address}:${test.port}/${test.database}?charSet=MS874"
userid="postgres"
password="xxxxx"
autocommit="true"
classpathref="maven.dependency.classpath"
onerror="continue"
encoding="MS874"
>
<fileset dir="src/test/sql">
<include name="serverSetup.sql"/>
</fileset>
</sql>


ในส่วนของ DBUnit ก็สามารถใช้ผ่าน ant เหมือนกัน
(หรืออาจะใช้ api ตรงๆใน testcase ก็ได้)
โดยมีวิธีใช้ดังนี้
<dbunit driver="${database.driver_class}"
supportBatchStatement="false"
url="${database.url}"
userid="${database.username}"
password="${database.password}">
<operation type="${operation}" src="${file}" format="xml"/>
</dbunit>


สิ่งที่แตกต่างกันก็คือถ้าเราใช้ sql task
เราจะต้องเตรียม data ด้วยคำสั่ง sql
ส่วนใน dbunit สามารถเตรียม dataset ใน
format xml ได้
กรณี fomat XmlDataSet
<?xml version="1.0" encoding="utf-8"?>
<dataset>
<table name='user_role'>
<column>username</column>
<column>role_name</column>
<row>
<value>tomcat</value>
<value>tomcat</value>
</row>
<row>
<value>mraible</value>
<value>admin</value>
</row>
</table>
</dataset>

กรณี format FlatXmlDataSet
<!DOCTYPE dataset SYSTEM "my-dataset.dtd">
<dataset>
<user_role username="tomcat"
role_name="tomcat"/>
</dataset>


สังเกตุว่าใน DBUnit Task จะมี Attribute operation
โดยเราสามารถระบุ operation ได้ดังนี้
  • UPDATE DBUnit จะตั้ง assumption ว่ามี data อยู่ใน Database แล้ว
    โดยพยายามจะนำ dataset ที่เตรียมไว้ไป update
  • INSERT ใช้ assumption ว่า ยังไม่มี table อยู่ใน Database
  • DELETE DBUnit จะ delete ข้อมูลใน table เฉพาะ
    ที่อยู่ใน dataset
  • DELETE_ALL delete ข้อมูลทุก row
    สำหรับ table ที่มีชื่ออยู่ใน DataSet
  • REFRESH ถ้า data มีอยู่แล้วใช้ update
    แต่ถ้ายังไม่มีใช้ insert
  • CLEAN_INSERT DBUnit จะ delete all
    ก่อนที่จะ insert ข้อมูลเข้าไป

Related link from Roti

Monday, May 16, 2005

ลองใช้ AppFuse

ติดตาม blog ของ Raible Design มาได้พักใหญ่แล้ว
ได้ยินเจ้า AppFuse มาหลายเดือนแล้ว ยังไม่ได้ลองสักที

พอดีมีโปรเจคใหม่อันหนึ่งเป็นโปรเจคเล็กๆ แค่แสดงความ
เป็นไปได้เฉยๆ ก็เลยวางแผนว่าจะใช้
Hibernate + Spring + Tapestry
แต่ปัญหาของโปรเจคใหม่ ก็คือ การ setup environment
ในการพัฒนา โดยกะว่าจะให้คนอื่นๆที่ร่วมทำสามารถ
เลือกได้ว่าจะใช้ netbeans หรือ eclipse ก็ได้
ทำให้ต้องเลือกวิธีการ build + test + deploy โดยใช้ ant
หรือ maven แทนที่จะอิงกับ feature ของ Ide

จากการนั่ง setup project โดยการใช้ maven
ก็จัดแจงไป download maven version ใหม่มา
จากนั้นก็นั่ง setup project structure, files
จากการทดสอบ build พบปัญหาว่าเจ้า xdoclet plugin ที่มากับ
maven 1.0.2 มันเปลี่ยน concept ใหม่ไปเยอะเลย
ทำให้ script เก่าๆที่เคยใช้ มัน run ไม่ผ่าน
ก็เลยต้องตัดใจ เพราะถ้าเอาไปพวกน้องๆที่มาช่วย code
ซึ่งไม่คุ้นเคยกับ maven เลย ก็คงจะ
สร้างความสับสน ตลอดจนเสียเวลาเรียนรู้และ setup เยอะ
ก็เลยไป load เจ้า AppFuse มาลองดู
(เป็นนิสัยเสียอย่างหนึ่งที่ได้ version ใหม่มาแล้ว
ก็ไม่อยากย้อนกลับไปใช้ version เก่า)

เจ้า concept ของ AppFuse ก็คือ
เป็นตัวช่วย kickstart ของโปรเจค
กล่าวคือ ตัวมันจะทำหน้าที่ generate
dummy project ให้เรา โดยมี function
ในระดับที่สามารถทดสอบ run ทดสอบเบื้องต้นได้ทันที
โดยตัว function ที่มีให้ก็คือ หน้าจอ login
, หน้าจอ main, edit profile ที่ถือว่าเป็น
หน้าจอบังคับของ web application
นอกจากนี้ยัง generate file, directory structure
ต่างๆที่พร้อมจะให้เรา coding, building, testing, deploy
ผ่านทาง ant ได้ทันที

การใช้งาน (คร่าวๆ)
  • Install AppFuse โดยเลือก Framework ที่ต้องการ
  • Install Ant (version 1.6.2+)
  • Install Jarkatar Tomcat
  • Install MySql (เป็น default database แต่ของผม ผมเลือกใช้ Postgres แทน)
  • config Environment Variable
  • สร้าง app ใหม่ด้วยคำสั่ง ant new
    ตัว AppFuse จะ generate project structure ให้เรา
  • cd ไปยัง project directory แล้วก็สั่ง ant setup
    แค่นี้เราก้ได้ dummy project ที่สามารถ run ได้แล้ว


จากการทดลองใช้ สิ่งที่ชอบก็คือ
project structure ที่ AppFuse สร้างให้เรา
ดูมีระเบียบดีมาก
แล้วก็ setup project ได้เร็ว ไม่ต้องนั่ง
หลังขดหลังแข็ง copy file จากโปรเจคเก่า

ส่วนข้อเสีย ก็คือขนาดของ project
มันใหญ่จัง ขนาดตั้ง 50 ​MB ไม่รู้ว่า
มันเอา library อะไรยัดมาให้เราบ้าง
คงต้องนั่งตัดเอา library ที่ไม่ใช้ออกเสียบ้าง

Related link from Roti