MODEL IN APACHE WICKET FRAMEWORK
Framework Apache Wicket thì Model là phần quan trọng nhất. Model chính là M trong mô hình MVC, là lớp trung gian chuyển dữ liệu giữa hai lớp là lớp View và lớp Domain (hay là Controller). Ở topic này xin được trình bày một số vấn đề của Model trong framework Wicket. Detaching Vấn đề ...
Framework Apache Wicket thì Model là phần quan trọng nhất. Model chính là M trong mô hình MVC, là lớp trung gian chuyển dữ liệu giữa hai lớp là lớp View và lớp Domain (hay là Controller).
Ở topic này xin được trình bày một số vấn đề của Model trong framework Wicket.
- Detaching
- Vấn đề Serialization với detachable model
- Nesting models
1. Detaching là gì
Chúng ta xem lại mô hình lớp của Model.
Lớp Model được thực thi interface IModel, IModel lại extends interface IDetachable. hàm detach() được quy định ở interface gốc.
Trong Wicket, khi một object là serialized thì các object referent đến nó cũng là serialized đệ quy. Đối với một page điều này có nghĩa là các component con liên hệ đến model đó thi cũng như là Model object nội tại của component đều là serialized. Việc này làm ứng dụng chiếm nhiều bộ nhớ, đặc biệt khi ứng dụng có nhiều người dùng.
Khi từng request đến ứng dụng (web) kết thúc, khi mà dữ liệu được render hoàn toàn trên browser thì, Wicket gọi tuần tự hàm detach() của tất cả các component và model thuộc request có lựa chọn làm sạch data. Việc làm này làm giảm thiểu chiếm dụng bộ nhớ của ứng dụng.
Dưới đây là mô hình sequence mô tả việc Wicket gọi hàm detach() sau khi một request kết thúc.
Ở mô hình sequence trên xử lý một request đơn giản, component Label truy vấn dữ liệu từ Model thông qua hàm getObject() để render trên page. Khi request kết thúc, Wicket yêu cầu component Label giải phóng dữ liệu trên cached bằng cách component gọi hàm detach() từ Model của nó. Trong khi thực hiện giải phóng data cached mà có lỗi xảy ra thì Wicket ghi lại log lỗi này và tiếp tục thực hiện detach cho các Model tiếp theo. Do vậy người dùng không thấy có lỗi nào xảy ra. Ta xét một ví dụ đơn giản cho việc lựa chọn detach data của Model bằng cách Override hàm detach() như sau.
public class NameModel implements IModel<String> { private IModel<Person> personModel; public NameModel(final IModel<Person> personModel){ this.personModel = personModel; } @Override public String getObject(){ return personModel.getObject().getName(); } @Override public void setObject(Stringobject){ personModel.getObject().setName(object); } @Override public void detach(){ personModel.detach(); } }
Trong ví dụ trên, hàm detach() đã được override. Khi hàm getObject() được gọi, request kết thúc thì hàm detach() được gọi để giải phóng data personModel.
Lưu ý: Person phải là Serialize object.
2. Các vấn đề serialization với detaching
Serialization là việc convert một object sang chuỗi byte. Ta có thể lưu nó dưới dạng file hay truyền đi với OutputStream, sau đó nó có thể được đọc và Deserializable.
Khi Model có một reference đến một object không phải là serializable, nếu chúng ta thực hiện detach để giải phóng object reference đó trước khi việc serialization diễn ra, và phục hồi lại chúng khi cần, thì việc này cần có giải pháp tốt. Giải pháp của chúng ta là xử lý ở hàm getObject() khi model được request nhiều lần.
Ta xét ví dụ sau.
public class CheeseModel extends Model { private Long id; private transient Cheese cheese; public CheeseModel() { } public CheeseModel(Cheese cheese) { setObject(cheese); } public CheeseModel(Long id) { this.id = id; } @Override public Object getObject() { if(cheese != null) return cheese; if(id == null ) { cheese = new Cheese(); } else { CheeseDao dao = ... cheese = dao.getCheese(id); } return cheese; } @Override public void setObject(Object object) { this. cheese = (Cheese)object; id = (cheese == null) ? null : cheese.getId(); } @Override public void detach() { this. cheese = null; } }
Trong ví dụ trên thì Cheese cheese là object non-serializable. Vậy với việc ghi lại hàm detach(), ta đã xử lý được vấn đề về object non-serializable.
3. Nesting models
Nhắc lại, Property model giải quyết vấn đề về giảm thiểu source code và làm việc với dữ liệu dạng dynamic. Detachable model đề cập ở trên thì thì giải quyết vấn đề giảm thiểu sữ dụng bộ nhớ và cho phép ta sử dụng các object không phải serialized.
Khi bạn muốn trả về một giá trị khác khi Model null thì hãy sử dụng Nesting Models.
public class DefaultWhenNullModel implements IModel { private static final long serialVersionUID = 1L; private final IModel mNestedModel; private final T mDefaultValue; public DefaultWhenNullModel(IModel nestedModel, T defaultValue) { mNestedModel = nestedModel; mDefaultValue = defaultValue; } public T getObject() { T val = mNestedModel.getObject(); return val == null ? mDefaultValue : val; } public void setObject(T object) { mNestedModel.setObject(object); } public void detach() { mNestedModel.detach(); } }