วันนี้อ่านพบ Hibernate 3.0 release แล้ว
ก็เลยตามดูว่า xdoclet มีความคืบหน้าในเรื่อง
การ support dtd ตัวใหม่ของ Hibernate 3.0
แค่ไหน
เท่าที่ตามเข้าไปดูใน xdoclet site
พบว่ามีสัญญาณที่ไม่ดีสำหรับ project นี้
โดยเฉพาะตัว xdoclet2 (ที่โปรยหัวไว้ 2 ปีมาแล้ว)
ใน cvs source ไม่พบว่ามี code ขยับมา 2 เดือนแล้ว
นอกจากนี้ก็ยังพบว่า ปีก่อนช่วงเดือน
june-november code ไม่ขยับเลย
เป็นอันปิดบัญชีสำหรับ xdoclet ไปได้แล้ว
ดังนั้นใน case Hibernate 3.0 ถ้าเกิดต้องใช้
ขึ้นมาคงต้องเข้าไปแก้ hibernate-module เองแล้ว
(ดีที่ architecture ของ xdoclet 1.x นั้น
ดีพอใช้อยู่แล้ว การเขียน module หรือ customize
module ก็เลยไม่หนักหนานัก)
Friday, April 01, 2005
ลง ingres r3 บน ubuntu
เมื่อวานเข้าไป load ingres database
(ซึ่งปัจจุบันเปลี่ยนเป็น opensource แล้ว)
เอามาลงบน notebook ของตัวเอง
ตัว package ของ ingres บน linux
อยู่ในรูป rpm
จึงต้องใช้ alien ในการแปลงให้เป็น debian-package ก่อน
โดยตัวที่จำเป็นในการลงก็มี
เนื่องจาก ingres ไม่ยอมให้ root เป็นคน start
จึงต้อง สร้าง user ingres และ group ingres เสียก่อน
จากนั้นก็ install package โดยใช้ command dpkg
จะได้ file อยู่ใน directory /opt/CA/IngresII
เนื่องจากผมยังไม่คล่อง linux มากนักเลยยังไม่รู้วิธี
ที่จะ overwrite user, group ใน debian package
ก็เลยใช้วิธี manual โดยใช้ chgrp, chown เอง
เมื่อลงเสร็จแล้วก็ให้
สั่ง setup database ด้วยคำสั่ง
(ใครที่ไม่เคยใช้ ingres ควรจะอ่านคู่มือ
เสียก่อน เนื่องจากมีหัวข้อที่ต้อง setup
พอสมควร)
สั่ง setup DAS
เท่านี้ก็เสร็จสิ้นขบวนการ
ในการใช้งานเราจะสั่ง start server ด้วยคำสั่ง ingstart
และ stop ด้วยคำสั่ง ingstop
(ซึ่งปัจจุบันเปลี่ยนเป็น opensource แล้ว)
เอามาลงบน notebook ของตัวเอง
ตัว package ของ ingres บน linux
อยู่ในรูป rpm
จึงต้องใช้ alien ในการแปลงให้เป็น debian-package ก่อน
โดยตัวที่จำเป็นในการลงก็มี
- ca-ingres_3.0.1-110_i386.deb -> core package
- ca-ingres-dbms_3.0.1-110_i386.deb -> database manager
- ca-ingres-das_3.0.1-110_i386.deb -> เพื่อให้ต่อ jdbc ได้
เนื่องจาก ingres ไม่ยอมให้ root เป็นคน start
จึงต้อง สร้าง user ingres และ group ingres เสียก่อน
จากนั้นก็ install package โดยใช้ command dpkg
จะได้ file อยู่ใน directory /opt/CA/IngresII
เนื่องจากผมยังไม่คล่อง linux มากนักเลยยังไม่รู้วิธี
ที่จะ overwrite user, group ใน debian package
ก็เลยใช้วิธี manual โดยใช้ chgrp, chown เอง
เมื่อลงเสร็จแล้วก็ให้
export II_SYSTEM=/opt/CA/IngresII
export PATH=$PATH:$II_SYSTEM/ingres/bin:$II_SYSTEM/ingres/utility
export LD_LIBRARY_PATH=$II_SYSTEM/ingres/lib
สั่ง setup database ด้วยคำสั่ง
(ใครที่ไม่เคยใช้ ingres ควรจะอ่านคู่มือ
เสียก่อน เนื่องจากมีหัวข้อที่ต้อง setup
พอสมควร)
iisudbms
สั่ง setup DAS
iisudas
เท่านี้ก็เสร็จสิ้นขบวนการ
ในการใช้งานเราจะสั่ง start server ด้วยคำสั่ง ingstart
และ stop ด้วยคำสั่ง ingstop
Related link from Roti
Thursday, March 31, 2005
Article Hibernate vs. Rails
หลังจากเริ่มเป็น Issue มาได้พักหนึ่ง
ในที่สุดก็มีคนเขียนบทความเปรียบเทียบระหว่าง
Hibernate กับ Active Record (Rails)
TheServerSide.com - Hibernate vs. Rails: The Persistence Showdown
เริ่มต้นก็เน้น Pattern ที่แตกต่างของทั้ง 2
ActiveRecord is "an object that wraps a row in a database table or view, encapsulates database access and adds domain logic on that data"[Fowler, 2003]. This means the ActiveRecord has "class" methods for finding instances, and each instance is responsible for saving, updating and deleting itself in the database. It's pretty well suited for simpler domain models, those where the tables closely resemble the domain model. It is also generally simpler then the more powerful, but complex Data Mapper pattern.
Data Mapper Pattern
The Data Mapper is "a layer of mappers that moves data between objects and a database while keeping them independent of each other and the mapper itself"[Fowler, 2003]. It moves the responsibility of persistence out of the domain object, and generally uses an identity map to maintain the relationship between the domain objects and the database. In addition, it often (and Hibernate does) use a Unit of Work (Session) to keep track of objects which are changed and make sure they persist correctly.
ในที่สุดก็มีคนเขียนบทความเปรียบเทียบระหว่าง
Hibernate กับ Active Record (Rails)
TheServerSide.com - Hibernate vs. Rails: The Persistence Showdown
เริ่มต้นก็เน้น Pattern ที่แตกต่างของทั้ง 2
ActiveRecord is "an object that wraps a row in a database table or view, encapsulates database access and adds domain logic on that data"[Fowler, 2003]. This means the ActiveRecord has "class" methods for finding instances, and each instance is responsible for saving, updating and deleting itself in the database. It's pretty well suited for simpler domain models, those where the tables closely resemble the domain model. It is also generally simpler then the more powerful, but complex Data Mapper pattern.
Data Mapper Pattern
The Data Mapper is "a layer of mappers that moves data between objects and a database while keeping them independent of each other and the mapper itself"[Fowler, 2003]. It moves the responsibility of persistence out of the domain object, and generally uses an identity map to maintain the relationship between the domain objects and the database. In addition, it often (and Hibernate does) use a Unit of Work (Session) to keep track of objects which are changed and make sure they persist correctly.
Related link from Roti
Wednesday, March 30, 2005
Ruby on Rails #2
ลองมาดูที่ Object Relation Mapping ก่อน
ตัว ruby on rails ใช้ Active Record
ลองดูหลักการเบื้องต้นก่อน
จะเห็นได้ว่า Powerfull เหลือเฟือเหลือใช้
เป็นทางเลือกอีกทางที่น่าสนใจ
ตัว ruby on rails ใช้ Active Record
ลองดูหลักการเบื้องต้นก่อน
- การ map เข้ากับ table
ใช้หลักง่ายๆก็คือ ชื่อ class ในรูปเอกพจน์ map กับ ชื่อ table ในรุปพหูพจน์class Person < ActiveRecord::Base
class person map เข้ากับ table persons
end
และ column ทุก column ใน table persons
automatic map เป็น property ของ class Person
Note: จะเห็นได้ว่าตัว class person ต้อง extend base class ที่ชื่อ ActiveRecord - การ map Relationship
class Project < ActiveRecord::Base
belongs_to :portfolio
has_one :project_manager
has_many :milestones
has_and_belongs_to_many :categories
end- belongs_to เป็นได้ทั้ง many-to-one หรือ one-to-one
โดย primary key ของ portfolios => foreign key ของ Projects - has_one มีลักษณะเป็น one-to-one
โดย primary key ของ project => foreign key ของ project_managers - has_many เป็น one-to-many
- has_and_belongs_to_many เป็น many-to-many โดยต้องมี table
หนึ่งสำหรับเก็บ pk ของทั้ง categories และ projects
โดย default table name จะใช้ชื่อว่า categories_projects (เรียงตามลำดับอักษร)
- belongs_to เป็นได้ทั้ง many-to-one หรือ one-to-one
- Aggregate Mapping (hibernate เรียก component mapping)
เป็นการ map attribute ตัวเดียวหรือหลายๆตัวเป็น objectclass Customer < ActiveRecord::Base
composed_of :balance, :class_name => "Money", :mapping => %w(balance amount)
composed_of :address, :mapping => [ %w(address_street street), %w(address_city city) ]
end- customer.balance จะมี datatype เป็น Money
โดย attribute ที่ชื่อ balance จะถูก pass เป็น
parameter ที่ชื่อ amount ใน Money Constructor Method - ส่วน customer.address จะมี datatype เป็น Address
โดยใช้ attribute address_street, address_citry
ในการ initialize Address object
- customer.balance จะมี datatype เป็น Money
- Validation
class Account < ActiveRecord::Base
validates_presence_of :subdomain, :name, :email_address, :password
validates_uniqueness_of :subdomain
validates_acceptance_of :terms_of_service, :on => :create
validates_confirmation_of :password, :email_address, :on => :create
end- presence_of -> Require
- uniqueness_of -> ค่าที่ set ต้อง unique ใน table
- acceptance_of -> case พิสดารหน่อย ไม่มีการเก็บลง table จริง
แต่ต้องการให้มีการ pass ค่ามา
(เห็นเขายกตัวอย่าง use case กรณี หน้าจอที่ต้อง tick accept license) - confirmation_of ->case พิสดารเช่นกัน เขายกตัวอย่างพวก password
confirmation ที่ค่า 2 ค่าต้องตรงกัน
- presence_of -> Require
- Self Relate RelationShip (พวกที่ structure เป็น tree)
class Item < ActiveRecord::Base
belongs_to :list
acts_as_list :scope => :list
end - Etc. -> Callback, Observers, Inheritance, Transaction
จะเห็นได้ว่า Powerfull เหลือเฟือเหลือใช้
เป็นทางเลือกอีกทางที่น่าสนใจ
Related link from Roti
Ruby on Rails #1
พักนี้อ่านเจอ blog ที่พูดถึง ruby on rails เยอะ
ก็เลยอยากรู้ว่าดีแค่ไหน
เท่าที่อ่านดู
ruby เป็น script language
rails เป็น Web Application framework
ดูจาก diagram ข้างล่างแล้วมี concept เป็น MVC แบบเดียวกับ struts เลย
ส่วนที่ต่างกัน ก็คงจะเป็นตรงที่ไม่ต้องเขียน Configuration file (พวก Action mapping)
แล้วก็ออกแบบมาสำหรับ web application ที่มี backend
เป็น database โดยเฉพาะ
การ install
ทดสอบสร้าง Hello world
Note: จะเห็นได้ว่าตัว Rail จะ map ชื่อcontroller เข้ากับ url ให้โดยอัตโนมัติ
แต่ยังไม่ได้ใช้ view เข้ามา render
ทดสอบต่อ Database
เข้าไป config file "config/database.yml"
Note: แค่เห็นว่าเตรียมแยก develop, test, production ให้ก็รู้สึกชอบใจแล้ว
สร้าง table "Categories"
สั่ง "ruby script/generate model Category"
สั่ง "ruby script/generate controller Category"
จะได้ file app/controllers/category_controller.rb
ให้แก้เนื้อหาใน file เป็น
จากนั้นเรียก url http://localhost:3000/category
จะได้ page ที่สามารถทำ create, update, delete, list
ได้
Note: rail จะ mapping ตัว model กับ table โดย model
ต้องอยู่ในรูป เอกพจน์ ส่วนชื่อ table ต้องอยู่ในรูป พหูพจน์
Note: การ insert เข้า Postgres ยังมีปัญหาในส่วนของ generate id อยู่ ยังไม่ได้เปิดคู่มือหาจริงๆจัง
ง่ายดีเหมือนกัน แต่ใช้ assumption ที่ต้องรู้กัน เยอะพอสมควร
ส่วนที่แสดงเป็นตัวอย่างอย่างง่าย แต่ถ้าทำใช้จริง
ก็จะต้องทำส่วน view plug เข้าไป เพื่อที่จะ
customize ให้มีหน้าตาที่ user รับได้
ก็เลยอยากรู้ว่าดีแค่ไหน
เท่าที่อ่านดู
ruby เป็น script language
rails เป็น Web Application framework
ดูจาก diagram ข้างล่างแล้วมี concept เป็น MVC แบบเดียวกับ struts เลย
ส่วนที่ต่างกัน ก็คงจะเป็นตรงที่ไม่ต้องเขียน Configuration file (พวก Action mapping)
แล้วก็ออกแบบมาสำหรับ web application ที่มี backend
เป็น database โดยเฉพาะ
การ install
- ใช้ synaptic install ruby1.8, libzlib-ruby, libyaml-ruby, libdrd-ruby, liberb-ruby, rdoc
- download rubygem (ทำหน้าที่เหมือน apt-get)
- extract rubygem.tar.gz, cd เข้าไปใน directory ที่ extract สั่ง "ruby setup.rb"
- สั่ง "gem install rails --remote"
- สั่ง "gem install postgres-pr" (กรณีใช้ postgresql เป็น backend)
ทดสอบสร้าง Hello world
- สั่ง "rails test" เพื่อทำการสร้าง project
ในขั้นนี้ rail จะ generate file ให้เราจำนวนหนึ่ง - สามารถทดลอง run ได้โดยสั่ง "ruby script/server" ใต้ project directory แล้วใช้ browser ชี้ไปยัง http://localhost:3000/
- สร้าง controller โดยใช้คำสั่ง "ruby script/generate controller Hello"
จะได้ file app/controllers/Hello_controller.rb - edit file Hello_controller.rb
class HelloController < ApplicationController
def index
render_text "hello world"
end
end - ทดลองเรียก http://localhost:3000/Hello
Note: จะเห็นได้ว่าตัว Rail จะ map ชื่อcontroller เข้ากับ url ให้โดยอัตโนมัติ
แต่ยังไม่ได้ใช้ view เข้ามา render
ทดสอบต่อ Database
เข้าไป config file "config/database.yml"
development:
adapter: postgresql
database: pphetra
host: localhost
username: pphetra
password: xxxxxxx
test:
adapter: postgresql
database: pphetra
host: localhost
username: pphetra
password: xxxxxxx
production:
adapter: postgresql
database: pphetra
host: localhost
username: pphetra
password: xxxxxxx
Note: แค่เห็นว่าเตรียมแยก develop, test, production ให้ก็รู้สึกชอบใจแล้ว
สร้าง table "Categories"
create table Categories (
id integer primary key not null default nextval('id'),
title varchar(255) not null,
description text
)
สั่ง "ruby script/generate model Category"
สั่ง "ruby script/generate controller Category"
จะได้ file app/controllers/category_controller.rb
ให้แก้เนื้อหาใน file เป็น
class CategoryController < ApplicationController
scaffold:Category
end
จากนั้นเรียก url http://localhost:3000/category
จะได้ page ที่สามารถทำ create, update, delete, list
ได้
Note: rail จะ mapping ตัว model กับ table โดย model
ต้องอยู่ในรูป เอกพจน์ ส่วนชื่อ table ต้องอยู่ในรูป พหูพจน์
Note: การ insert เข้า Postgres ยังมีปัญหาในส่วนของ generate id อยู่ ยังไม่ได้เปิดคู่มือหาจริงๆจัง
ง่ายดีเหมือนกัน แต่ใช้ assumption ที่ต้องรู้กัน เยอะพอสมควร
ส่วนที่แสดงเป็นตัวอย่างอย่างง่าย แต่ถ้าทำใช้จริง
ก็จะต้องทำส่วน view plug เข้าไป เพื่อที่จะ
customize ให้มีหน้าตาที่ user รับได้
Related link from Roti
Monday, March 28, 2005
วันนี้เห็น stack trace ของ blogger
วันนี้ post ข้อมุลแล้วเกิด exception เลยได้เห็น stack trace ของ blogger
ก็เลยใช้วิชาเดาเข้ามาช่วย
ตัว blogger ใช้ tomcat 4.x เป็น app server
ตัว web server นั้นไม่รู้ รู้แต่ว่าใช้ jk เป็นตัวแจก request ให้ tomcat
และน่าจะใช้ sticky session ด้วยเพราะมี cookie ตัวหนึ่งที่เก็บค่า serverId
(ใครที่ยังไม่เคยใช้ tomcat cluster อ่านเพิ่มเติมได้ที่นี่ link)
จากนั้นก็เข้าสู่ framework ของ google
(มีบางส่วนเป็น pyra framework) ที่วางลักษณะ
เป็น pipe chain กับ Handler chain
เท่าที่เห็นก็มี
ก็เลยใช้วิชาเดาเข้ามาช่วย
ตัว blogger ใช้ tomcat 4.x เป็น app server
ตัว web server นั้นไม่รู้ รู้แต่ว่าใช้ jk เป็นตัวแจก request ให้ tomcat
และน่าจะใช้ sticky session ด้วยเพราะมี cookie ตัวหนึ่งที่เก็บค่า serverId
(ใครที่ยังไม่เคยใช้ tomcat cluster อ่านเพิ่มเติมได้ที่นี่ link)
จากนั้นก็เข้าสู่ framework ของ google
(มีบางส่วนเป็น pyra framework) ที่วางลักษณะ
เป็น pipe chain กับ Handler chain
เท่าที่เห็นก็มี
- IdentityCookiePipe ไม่รู้ว่าเก็บอะไร เพราะ encode ไว้ (ข้อมูลอยู่ใน cookie ที่ชื่อ I)
- StatsPipe -> สถิติ
- ProfileLogPipe ->น่าจะ update lastupdate, กับ logging
- PyraJspDispatchPipe ->framework ของ Pyra ซึ่งมี handler chain
- AuthenticatedHandler
- ActionHandler -> ตัวนี้น่าจะเก็บ post ลง database
- PublishHandler -> ตัวนี้น่าจะ generate cache page เก็บไว้
java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start(Native Method)
at com.pyra.blogger.Blog.publishAsync(Blog.java:1938)
at com.pyra.blogger.frontend.PublishHandler.perform(PublishHandler.java:133)
at com.google.servlet.handlers.ActionHandler.execute(ActionHandler.java:27)
at com.google.servlet.handlers.AuthenticatedHandler.execute(AuthenticatedHandler.java:106)
at com.google.servlet.pipe.HandlerDispatchPipe.invoke(HandlerDispatchPipe.java:82)
at com.pyra.blogger.frontend.PyraJspDispatchPipe.invoke(PyraJspDispatchPipe.java:71)
at com.google.servlet.pipe.ServletPipe.invokeNextPipe(ServletPipe.java:118)
at com.pyra.blogger.frontend.ProfileLogPipe.invoke(ProfileLogPipe.java:48)
at com.google.servlet.pipe.ServletPipe.invokeNextPipe(ServletPipe.java:118)
at com.google.servlet.pipe.StatsPipe.invoke(StatsPipe.java:64)
at com.google.servlet.pipe.ServletPipe.invokeNextPipe(ServletPipe.java:118)
at com.google.servlet.pipe.PendingRequestPipe.invoke(PendingRequestPipe.java:31)
at com.google.servlet.pipe.ServletPipe.invokeNextPipe(ServletPipe.java:118)
at com.google.servlet.pipe.HttpRedirectPipe.invoke(HttpRedirectPipe.java:43)
at com.google.servlet.pipe.ServletPipe.invokeNextPipe(ServletPipe.java:118)
at com.pyra.blogger.frontend.IdentityCookiePipe.invoke(IdentityCookiePipe.java:137)
at com.google.servlet.pipe.ServletPipe.invokeNextPipe(ServletPipe.java:118)
at com.google.servlet.exceptionhandling.ExceptionHandlerPipe.invoke(ExceptionHandlerPipe.java:99)
at com.google.servlet.pipe.ServletPipe.invokeNextPipe(ServletPipe.java:118)
at com.google.servlet.pipe.LocaleContextPipe.invoke(LocaleContextPipe.java:116)
at com.google.servlet.BaseServlet.doGet(BaseServlet.java:89)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:740)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:247)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:256)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:494)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
at org.apache.catalina.core.StandardContext.invoke(StandardContext.java:2415)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:180)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
at org.apache.catalina.valves.ErrorDispatcherValve.invoke(ErrorDispatcherValve.java:171)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:172)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:174)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
at org.apache.coyote.tomcat4.CoyoteAdapter.service(CoyoteAdapter.java:223)
at org.apache.jk.server.JkCoyoteHandler.invoke(JkCoyoteHandler.java:261)
at org.apache.jk.common.HandlerRequest.invoke(HandlerRequest.java:360)
at org.apache.jk.common.ChannelSocket.invoke(ChannelSocket.java:604)
at org.apache.jk.common.ChannelSocket.processConnection(ChannelSocket.java:562)
at org.apache.jk.common.SocketConnection.runIt(ChannelSocket.java:679)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:619)
at java.lang.Thread.run(Thread.java:534)
Related link from Roti
Transitive dependencies management
Ivy เป็น tool ตัวหนึ่งที่ช่วยจัดการ dependency library
สมมติว่า project เรา depend on project X
และ project X depend on project Y
เวลาเราเชียน build script ด้วย maven
เราต้องระบุว่า project เรา depend กับทั้ง
proejct Y และ Y
แต่สำหรับ Ivy แล้ว เราจะระบุ dependency
แค่กับ project X เท่านั้น ส่วน x จะไป
depend กับใคร ตัว Ivy จะ solve ให้เอง
feature Transitive dependencies ช่วย
ให้เราจัดการ dependency ได้ง่ายขึ้น
อย่าง project ล่าสุดของผม ใน maven ผม
ต้องระบุ dependency กับ jar ทั้งหมด
40 file แต่ถ้าเป็น Ivy, dependency ที่ต้องระบุ
จะเหลือแค่ 15 file
สมมติว่า project เรา depend on project X
และ project X depend on project Y
เวลาเราเชียน build script ด้วย maven
เราต้องระบุว่า project เรา depend กับทั้ง
proejct Y และ Y
แต่สำหรับ Ivy แล้ว เราจะระบุ dependency
แค่กับ project X เท่านั้น ส่วน x จะไป
depend กับใคร ตัว Ivy จะ solve ให้เอง
feature Transitive dependencies ช่วย
ให้เราจัดการ dependency ได้ง่ายขึ้น
อย่าง project ล่าสุดของผม ใน maven ผม
ต้องระบุ dependency กับ jar ทั้งหมด
40 file แต่ถ้าเป็น Ivy, dependency ที่ต้องระบุ
จะเหลือแค่ 15 file
Related link from Roti
ตัวอย่าง Tapestry Ajax component
มีคนทดลองทำ Ajax style component อยู่ที่ XTile example
ดูตามที่เขาเขียนแล้ว ok เลย
xtile เป็น invisible component
ทำหน้าที่เป็นตัว call xmlhttprequest
เข้าไปยัง Page Listener
ชอบที่ call ตรงเข้า page listener เลย
ทำให้ source code ไม่กระจัดกระจาย
ดูตามที่เขาเขียนแล้ว ok เลย
xtile เป็น invisible component
ทำหน้าที่เป็นตัว call xmlhttprequest
เข้าไปยัง Page Listener
ชอบที่ call ตรงเข้า page listener เลย
ทำให้ source code ไม่กระจัดกระจาย
Related link from Roti
Subscribe to:
Posts (Atom)