- Mô ̣t thẻ flashcard bao gồm: tƣ̀, nghĩa, tƣ̀ đồng nghĩa, tƣ̀ trái nghĩa.
- Mỗi tƣ̀ có thể có nhiều nghĩa và do đó có thể ta ̣o nhiều flashcard cho cùng mô ̣t tƣ̀.
Hình 37. Trang kiểm tra trí nhớ.
Trang này cho phép ta cho ̣n mô ̣t danh sách tƣ̀ không rỗng (có flashcard) và nó sẽ lấy ngẫu nhiên mô ̣t trong các thành phần của flashcard để hiển thi ̣. Ngƣời dùng có nhiê ̣m vu ̣ nhâ ̣p tƣ̀ vào ô để kiểm tra khả năng ghi nhớ của mình.
VII. Tổng kết cá c di ̣ch vu ̣ đã sƣ̉ du ̣ng:
Mục này sẽ tổng kết lại những dịch vụ GEA đã đƣợc sử dụng trong ứng dụng và lý giải vì sao lại sử dụng chúng.
Sinh viên thực hiê ̣n : Đào Phan Quang K50 Lớp CNPM 76
VII.1. Dịch vụ Account : dùng để quản lý việc đăng nhập vào ứng dụng . Khi
xây dƣ̣ng cơ chế xác thƣ̣ c cho ƣ́ng du ̣ng ta có thể tƣ̣ xây dƣ̣ng cơ chế này nhƣ vẫn xây dƣ̣ng trên các hê ̣ thống cổ điển . Tuy nhiên khi cân nhắc đến vấn đề liê ̣u ta có nhất thiết phải xây dƣ̣ng mới không khi mà ta khó có thể đƣa ƣ́ng du ̣ng của ta ra và chạy trên một nền tảng khác , ta thấy sẽ là phí công sƣ́c khi xây dƣ̣ng mớ i mô ̣t hê ̣ thống xác nhâ ̣n ngƣời dùng.
package com.eel.server; import javax.jdo.PersistenceManager; import com.eel.client.LoginService; import com.eel.shared.FriendList; import com.eel.shared.LoginInfo; import com.eel.shared.UserProfile; import com.google.appengine.api.users.User; import com.google.appengine.api.users.UserService; import com.google.appengine.api.users.UserServiceFactory; import com.google.gwt.user.server.rpc.RemoteServiceServlet; @SuppressWarnings("serial")
public class LoginServiceImpl extends RemoteServiceServlet implements LoginService {
public LoginInfo login(String requestUri) {
PersistenceManager pm = PMF.get().getPersistenceManager(); UserService userService =
UserServiceFactory.getUserService();
User user = userService.getCurrentUser(); LoginInfo loginInfo = new LoginInfo(); if (user != null) { loginInfo.setLoggedIn(true); loginInfo.setEmailAddress(user.getEmail()); try{ UserProfile u = pm.getObjectById(UserProfile.class, user.getEmail()); loginInfo.setNickname(u.getDisplayname()); pm.close(); }catch(Exception e){ UserProfile u = new UserProfile(user.getEmail(),user.getNickname());
FriendList fl = new FriendList(user.getEmail()); pm.makePersistent(u);
pm.makePersistent(fl);
loginInfo.setNickname(user.getNickname()); pm.close();
Sinh viên thực hiê ̣n : Đào Phan Quang K50 Lớp CNPM 77 loginInfo.setLogoutUrl(userService.createLogoutURL(requestUri)); } else { loginInfo.setLoggedIn(false); loginInfo.setLoginUrl(userService.createLoginURL(requestUri)); } return loginInfo; } }
VII.2. Dịch vụ Image : dùng trong việc giảm giữ liệu chuyển về client khi client yêu cầu xem ảnh đa ̣i diê ̣n và thumbn ail các ảnh đƣợc ngƣời dùng tải lên .Do ảnh đƣợc ngƣời dùng tải lên có thể có dung lƣợng và kích thƣớc lớn những các ảnh đa ̣i diê ̣n hay ảnh hiển thi ̣ thumbnail chỉ có kich thƣớc nhỏ , sẽ là phí phạm băng thông nếu ta truyền cả bức ảnh lớn mỗi lần đƣợc yêu cầu.
package com.eel.server; import java.io.IOException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.google.appengine.api.blobstore.BlobKey; import com.google.appengine.api.images.Image; import com.google.appengine.api.images.ImagesService; import com.google.appengine.api.images.ImagesServiceFactory; import com.google.appengine.api.images.Transform; @SuppressWarnings("serial")
public class Serve extends HttpServlet { private ImagesService imagesService = ImagesServiceFactory.getImagesService();
public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
BlobKey blobKey = new BlobKey(req.getParameter("blob-key")); //blobstoreService.serve(blobKey, res);
Image image = ImagesServiceFactory.makeImageFromBlob(blobKey); Transform resize = ImagesServiceFactory.makeResize(100, 150); image = imagesService.applyTransform(resize, image);
res.setContentType("image/jpeg");
res.setHeader("Content-Disposition", "attachment; filename=\"" + "test" + '"');
res.getOutputStream().write(image.getImageData()); res.getOutputStream().flush();
Sinh viên thực hiê ̣n : Đào Phan Quang K50 Lớp CNPM 78
} }
Trong đồ án ta chỉ dùng mô ̣t phép biển đổi đơn giản là thu nhỏ kích thƣớc của ảnh.
VII.3. Blobstore : ta dù ng di ̣ch vu ̣ này để lƣu ảnh đa ̣ i diê ̣n của ngƣời dùng và các tập tin tài nguyên mà ngƣời dùng tải lên . Dịch vụ này sử dụng hơi khác khi kết hơ ̣p với GWT do yêu cầu gƣ̉i nô ̣i dung tâ ̣p tin trong mô ̣t yêu cầu HTTP POST .
- Phải tạo một form với method là post , encode là multipart, action phải là giá trị tạo bởi dịch vụ blobstore
public String getUploadURL(String s) { BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
Return blobstoreService.createUploadUrl(s); }
- Phải có mô ̣t servlet để xƣ̉ lý khóa của các blob , đi ̣a chỉ URL của servlet này đƣơ ̣c đƣa vào làm đối số cho hàm createUploadUrl ở trên.
package com.eel.server; import java.io.IOException; import java.util.Date; import java.util.Map; import javax.jdo.PersistenceManager; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.eel.shared.DataBlock; import com.google.appengine.api.blobstore.BlobKey; import com.google.appengine.api.blobstore.BlobstoreService; import com.google.appengine.api.blobstore.BlobstoreServiceFactory; @SuppressWarnings("serial")
public class Upload extends HttpServlet {
private BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
Map<String, BlobKey> blobs = blobstoreService.getUploadedBlobs(req);
BlobKey blobKey = blobs.get("myFile");
PersistenceManager pm = PMF.get().getPersistenceManager();
Sinh viên thực hiê ̣n : Đào Phan Quang K50 Lớp CNPM 79
String owner = req.getParameter("owner"); String name = req.getParameter("name"); String type = req.getParameter("type"); Date d = new Date();
DataBlock bw = new DataBlock(blobKey.getKeyString(),d,name,type,owner); pm.makePersistent(bw); pm.close(); } } }
VII.4. Mail và Taskqueue : ứng dụng sử dụng 2 dịch vụ này để gửi mail mời
đến những ngƣời chƣa từng đăng nhập vào hệ thống . Mô ̣t ngƣời dùng sẽ điền vào đi ̣a chỉ mail của ngƣời ba ̣n mà ho ̣ muốn mời tham gia vào cô ̣ng đồng .
VII.5. Memcache : ứng dụng sử dụng dịch vụ này để lƣu ảnh đại diện của
ngƣời dùng , do luôn có nhu cầu sƣ̉ du ̣ng ảnh đa ̣i diê ̣n nên ta nên lƣu nó vào
memcache nhằm giảm lƣợng truy câ ̣p và dƣ̃ liê ̣u lấy tƣ̀ datastore (do đó giảm chi phí và tăng tốc độ ứng dụng).
VIII. Các vấn đề nhận thấy trong quá trình phát triển ứng dụng:
- GEA giới ha ̣n không cho phép ta ̣o thêm luồng mới , điều này gây khó khăn khi triển khai các giải pháp yêu cầu ta ̣o các luồng xƣ̉ lý mới. Ví dụ nhƣ chức năng tải tâ ̣p tin lên , nếu muốn xƣ̉ lý nô ̣i dung của tâ ̣p tin đó thì phải xƣ̉ lý hồn tồn bằng mợt giải pháp java . Tuy nhiên nếu thƣ̣c hiê ̣n trên mô ̣t máy chủ Window /Linux ta có thể cài đă ̣t mô ̣t công cu ̣ phâ n tích và go ̣i hàm console để xƣ̉ lý.
- GWT và GEA tuy cùng của Google nhƣng không hoàn toàn tƣơng thích . Điều này thấy rõ nhất ở viê ̣c tổ chƣ́c cơ sở dƣ̃ liê ̣u , các lớp có thể sử dụng để truyền qua RPC rất ha ̣n chế . Đơn giản n hƣ viê ̣c truyền các đối tƣợng kiểu Collection (nhƣ List, Map…) là không đƣợc . Ta phải chuyển chúng về kiểu mảng cơ bản. Hoă ̣c nhƣ di ̣ch vu ̣ blobstore chƣa thể truyển dƣ̃ liê ̣u của tâ ̣p tin tải lên qua RPC.
- GEA không cho phép ta ̣o mới tâ ̣ p tin, điều này bắt buô ̣c thông tin phải lƣu vào cơ sở dữ liệu.
- GEA cũng không tƣơng thích với tất cả framework phổ bi ến hiện nay . Nhƣ Hibernate hoàn toàn không tƣơng thích , Struts cần work -around mới có thể hoạt đông.
- GEA gắn chă ̣t với giao thƣ́c HTTP , và một số cổng nhất định (80,443). Điều này gây hạn chế cho các loại ứng dụng yêu cầu các giao thức khác .
Sinh viên thực hiê ̣n : Đào Phan Quang K50 Lớp CNPM 80
KẾT LUẬN
1. Kết quả thu đƣơ ̣c:
Trong quá trình làm đồ án, em đã đa ̣t đƣợc mô ̣t số kết quả sau: - Hiểu rõ các lợi ích của điê ̣n toán đám mây.
- Tìm hiểu đƣợc một cài đặt cụ thể của điện toán đám mây là dịch vụ GEA . - Làm chủ đƣợc môi trƣờng phát triển ứng dụng Java của GEA.
- Gián tiếp tìm hiểu một công nghệ phát triển frontend là GWT và kiến trúc lâ ̣p trình MVP.
- Xây dƣ̣ng đƣợc mô ̣t ƣ́ng du ̣ng trên nền tảng di ̣ch vu ̣ GEA, tƣ̀ đó có cái kinh nghiê ̣m khi xƣ̉ lý các vấn đề lâ ̣p trình khi xây dƣ̣ng ƣ́ng du ̣ng trên GEA
2. Hạn chế:
Do thời gian han he ̣p của quá trình làm đồ án và viê ̣c thƣ̣c hiê ̣n đồ án mô ̣t mình nên chƣơng trình chỉ thƣ̣c hiê ̣n các chƣ́c năng cơ bản nhằm liên kết các di ̣ch vu ̣ của GEA vào trong mô ̣t ƣ́ng du ̣ng thƣ̣c tế và không tránh khỏi có thể có lỗi hay c ác xử lý có thể mang tính chủ quan . Mô ̣t ha ̣n chế nƣ̃a là ƣ́ng du ̣ng chƣa sƣ̉ du ̣ng mô ̣t framework nào. Tuy GEA không phải là tƣơng thích với mo ̣i framework nhƣng viê ̣c sƣ̉ du ̣ng mô ̣t framework không đƣợc hỗ trợ đầy đủ là mô ̣t kinh nghi ệm quý cho việc thƣ̉ nghiê ̣m phát triển ƣ́ng dung.
3. Hƣớ ng phát triển:
Nhƣ̃ng vấn đề giải quyết trong đồ án là nền tảng cơ bản nhất cho các ƣ́ng du ̣ng trên di ̣ch vu ̣ GEA. Còn rất nhiều vấn đề có thể phát triển:
- Về mă ̣t chƣ́c năng có thể bổ sung thêm cơ chế cho viê ̣c ho ̣c các kỹ năng khác nhƣ nghe, nói.
- Hiê ̣u năng có thể đƣợc nâng cao bằng viê ̣c tối ƣu hóa mã nguồn ƣ́ng du ̣ng , cả hai phần GWT và mã sƣ̉ du ̣ng di ̣ch vu ̣ GEA.
- Cần thƣ̉ nghiê ̣m tốc đô ̣ và tối ƣu hóa hiê ̣u quả truy vấn dƣ̃ liê ̣u.
- Cài đặt việc sử dụng hệ thống memcache để tăng hiệu năng ứng dụng . - Khai thác nhƣ̃ng thông tin của ngƣời dùng để trợ giúp quyết đi ̣nh lƣ̣a cho ̣n .
Sinh viên thực hiê ̣n : Đào Phan Quang K50 Lớp CNPM 81
Tài liệu tham khảo
[1] Michael Armbrust, Armando Fox, Rean Griffith, Anthony D.Joseph, Randy Katz, Andy Konwinski, Gunho Lee, David Patterson, Ariel Rabkin, Ion Stoica and Matei Zaharia, “Above the Clouds : A Berkeley View of Cloud Computing”, UC Berkeley Reliable Adaptive Distributed Systems Laboratory, 10/2/2009, http:// www.eecs.berkeley.edu/Pubs/TechRpts/ 2009/ EECS-2009-28.html.
[2] iBm Center for the Business of Government, “Moving to the cloud: An introduction to cloud computing in government”, 2009, http://www.businessofgovernment.us/pdfs/WyldCloudReport.pdf
[3] Tahir Akram, “Developing Java Web Applications In Google App Engine”, 19/12/2009, slide tại trang www.slideshare.net.
[4] Google App Engine Documentation , http://code.google.com/appengine/ [5] Fay Chang, Jeffrey Dean, Sanjay Ghemawat, Wilson C. Hsieh, Deborah A.
Wallach, “Bigtable: A Distributed Storage System for Structured Data”, OSDI 2006, http://labs.google.com/papers/bigtable.html.
[6] SanjayGhemawat ,HowardGobioff, and Shun-TakLeung, “The Google File System”, 2003, http://labs.google.com/papers/gfs-sosp2003.pdf
[7] Google Web Toolkit Documentation , http://code.google.com/webtoolkit/ [8] Ryan Dewsbury, “Google Web Toolkit Application”, 2009, NXB Prentice
Hall.
[9] Rick Hightower, 3 phần của “Google App Engine for Java” , 8/2009, http://www.ibm.com/developerworks/java/library/j-gaej1/.