2012年3月30日 星期五

區分 GWT 程式碼的執行環境

這是在勁過呂布的噗浪上遇到的問題。

起因是傳給 String.split() 的 RegExp,Java 與 JavaScript 的寫法相似、但不是完全相同(參見 GWT 文件),也就會遇到「development mode 下正確、但 compile 之後得不到預期結果」的窘況。再者,如果 client/server 端都用 Java 寫,也會擴大這個問題的麻煩度。

這時候我們需要 GWT

(謎之聲:你不就在寫 GWT 了 [指])

這裡是指 com.google.gwt.core.client.GWT。這個 class 提供 isClient()isScript()isProdMode() 理論上與 isScript() 等意)這兩個 static method。

isScript() 是辨別程式碼是以 JavaScript 的方式執行、還是以 Java 的方式執行。在 development mode 下會回傳 false,在 compile 時才由 GWT compiler 改成回傳 true。

isClient()(邏輯上)不會區分是不是 development mode,純粹辨別程式碼是在瀏覽器上頭執行,還是在 JVM 上頭執行。

理解這種文字遊戲有點麻煩,還是來寫個程式比較實在。首先是 client 端的程式:
public class Foo extends Composite
 public static final RpcServiceAsync rpc = GWT.create(RpcService.class);
 private VerticalPanel panel = new VerticalPanel();
 public Foo(){
  String result = "[client] GWT.isClient() = " + GWT.isClient()
    + ", GWT.isScript() = " + GWT.isScript();
  panel.add(new Label(result));

  rpc.gwtMethod(new AsyncCallback<String>() {
   @Override
   public void onSuccess(String result) {
    panel.add(new Label("[server] "+result));
   }
   
   @Override
   public void onFailure(Throwable caught) {}
  });
  
  this.initWidget(panel);
 }
}

而 Server 端 RpcServiceImpl 的 method 長這樣:
 public String gwtMethod() {
  return "GWT.isClient() = "+GWT.isClient()
   + ", GWT.isScript() = "+GWT.isScript();
 }

在 development mode 下,會得到:
[client] GWT.isClient() = true, GWT.isScript() = false
[server] GWT.isClient() = false, GWT.isScript() = false
實際 deploy 到 web server 上,會得到:
[client] GWT.isClient() = true, GWT.isScript() = true
[server] GWT.isClient() = false, GWT.isScript() = false
如此一來,雖然遇到了抽象滲漏的現象,但我們還是可以藉由  GWT.isClient()GWT.isScript() 判斷是 development mode 還是 production mode、是 client 端還是 server 端、給予對應 RegExp,來解決這個問題。

2012年3月28日 星期三

App Engine 1.6.4 發佈

原文網址:App Engine 1.6.4 Released

App Engine 三月份持續發佈塞滿新功能、系統改進與錯誤修復的新版本。在我們朝 Google I/O 前期議程邁進的同時,我們也持續專注在使產品更光鮮亮麗,這個釋出的版本就是一個閃閃發光的例子。

系統面的改變

  • Log:現在新的 log 儲存設定可以是一個月,而超過你指定界線的 log 將會被刪除。
  • Datastore Index 統計資料:Admin Console 的 Datastore Statistics 頁面現在會在 Datastore Entity 後頭顯示 Index 所佔用的儲存空間量。
  • Blobstore 遷移功能:Datastore Migration 工具現在包含一個實驗階段的選項,可以讓你在 M/S 與 HRD 之間搬移 Blobstore 物件。我們強烈建議所有的 application 都改用 HRD。
  • Datastore 備份至 Google Cloud Storage:在 1.6.3 版中,我們推出了 Blobstore 的備份還原功能:而在這個版本中,我們增加將資料備份到 Google Cloud Storage 的功能。
  • Memcache Viewer:我們導入了一個功能,可以觀看 memcache 的統計資料、以及輸入 key 值來查看對應的 memcache entry。
  • 從 Google Cloud Storage 提供資料:現在不但可以從 Blobstore 提供 blob,也可以由 Google Cloud Storage 直接提供。

Runtime 的改變

  • Thread:Java 與 Python 都提供執行 backend 時有 background thread 這個實驗階段的功能。此外,我們讓 Java 也能像 Python 2.7 一樣在處理 frontend request 時可以使用 thread。

Datastore framework 的改變

  • Python 的 NDB:NDB API 已經脫離實驗階段,成為完整支援的功能。這個新一代的 Datastore API 加強資料模組化、查詢、並從裡到外地支援非同步計算。
  • JPA 2 與 JDO 3:我們已經針對 App Engine 的 DataNucleus plugin 做出顯著的改善。這個實驗中的 plugin 版本為 2.0,增加 JPA 2、JDO 3 的支援,以及超過 40 個錯誤修正。這裡有列出完整的版本更新紀錄。

上面這些還不是全部,你可以在版本更新紀錄中(Python 版Java 版)得知所有的新功能與錯誤修正。請將你所有的回饋意見送到我們的 Google Group;如果你有什麼程式方面的問題,可以在 Stack Overflow 上找尋來自我們或其他優秀開發者的協助。

2012年3月1日 星期四

App Engine 1.6.3 發佈

今年的第二個版本,讓你可以馬上開始使用這些新功能。有什麼可以比在你的 application 支援 A/B Testing、或是從你的 Google App domain 寄信時使用 DKIM 簽章,還更令人興奮呢?(謎之聲:降低收費啊!笨蛋!)這個版本有許多令人興奮的變化,讓你在今年多出來的這天保持忙碌。