2013年10月27日

Upgrade 我的 Snow Leopard 到 Mavericks

使用 OSX 10.6 有一段時間了,對於 software development 來說開始有些不方便了;像是 XCode 工具的版本限制以及 OpenJDK 7 安裝問題等。自從 Apple 公司發表新款 iPhone 5S/C 與 iPad Air 同時,突然佛心來著,OSX 10.9 提供免費升級:
當然,對個人來說簡直提天掉下來的禮物,於是開始著手安裝。
(1) 程序上總是先求保險,得準備第 2 顆硬碟進行資料備份:
(2) 設定第 2 顆硬碟開機,測試並確認資料有抄寫:
(3) 無誤後再設回原開機磁碟,重開機後開始下載安裝:
安裝完畢後,便是檢查所有常用應用程式的相容問題;多數情形下使用系統更新作業或程式換版就可以解決了。不過,最麻煩的是得下載幾個重量級的更新,例如:XCode;而且原系統中的 JDK 6 會被移除,須自行下載與安裝 Java for OS X 2013-005。

整個升級的過程最需的是體力與細心,因為備份時的資料整理與枯等,安裝後的目錄、檔案的移置、缺漏確認等,所需的時間很長不消十數小時。萬一不小心,大多資料的遺失可是會損失慘重。

而初步的使用心得,有 3 個小地方待適應:
(1) mouse / pad 的 scrolling 手勢方向與 v10.6 相反
(2) [swipe between pages] 手勢的功能,因不熟悉而常將正在瀏覧的頁面切到上一頁或下一頁
(3) 輸入法 hint 與過去的方式有點不同,尤其是標點符點的字鍵有更動,會一時之間找不到

that's it!

ps. 另外,中文字體看起怪怪、醜醜的

2013年10月15日

Multiple assignment in Groovy

在 Groovy 的說明資料中提到, 物件可以進行 multiple assignment。從其範例可看出 values 是 List 型別的: ...The syntax works for arrays as well as lists, as well as methods that return either of these...。

在 HA.KI blog 的範例 中最後一個也舉出了使用 regular expression 的技巧:
def money  = '12 Euro'
def regexp = /(\d+) (\w+)/
def (exp, amount, currency) = (money =~ regexp)[0]

assert '12' == amount
assert 'Euro' == currency

不過, 對於 List 的表述方式:
listObject[index]
// 或
listObject.get(index) // 保守寫法: listObject?.get(index)
是存在當掉的風險的, 因為 index 有可能超過索引範圍。
以上例來說, 只要 money 的值不是依  '數值 幣別'  呈現就會發生。 (例如 'Euro  12')

所以, 可以改善的技巧是用 inject() [參考上篇Groovy 的 inject() method 應用] 來呈現 List 物件即可:
def (exp, amount, currency) = (money =~ regexp)?.inject([]) { res, itm ->
    res += itm
}
ps. 參考資訊 http://rosettacode.org/wiki/Return_multiple_values

2013年10月5日

GVM 與 GroovyServ

執行 .groovy code 不外乎要設定 PATH 與 CLASSPATH,以找到 interpreter(groovy)、compiler(groovyc) 與相關的 library;它往往需要在啟動的 shell 或 user profile 來加以處理。但,以系統維運的角度來說,則需要"安裝",以便整合至 environment 之中,維持系統固定、一致版本的 interpreter 與 compiler。以 ubuntu 系統為例:
sudo apt-add-repository ppa:groovy-dev/groovy
sudo apt-get update
sudo apt-get install groovy

groovy -version

Groovy Version: 1.8.6 JVM: ...
使得 groovy script 有如 shell script 一般,只要在 script 的第一行指出 interpreter 即可:
#!/usr/bin/bash
# this is a bash shell script

echo "1 + 2 = $((1+2))"

# ...
#!/usr/bin/env groovy
// this is a groovy script

println "1 + 2 = ${1+2}"

// ...

另一種安裝的選擇:GVM;它有如 linux 的 alternatives 來管理不同版本的 package 路徑一般 (alternatives 可用來安裝多版本 JDK),安裝後並指定 groovy 的版本。使得 groovy script 的第一行寫法保持一致、不受影響。

話說 language ,不免會被拿來與過去熟知的做比較;Java 也曾被"提過"很慢,但隨時代的演進這已是不再拿來作文章的話題了。近年來 JVM 上熱門的 dynamic language:Groovy ;也一樣引起話題:慢。

也就是說 script 會因功能的增加而 source code 越來越長,也造成編譯與執行的時間相對變長;這往往會造成 developer 的困擾。這種在編譯時期一樣有這"症頭"的還有 Scala;不過,人家它有 fsc;那 Groovy 呢?

還好出現了 GroovyServ。

以抓取某熱門森林遊樂區的訂房首頁的應用為例:
僅使用 groovy interpreter,執行的時間:
real 0m6.180s
user 0m4.875s
sys  0m0.271s
而搭配 GroovyServ 使用,在執行一次以後則:
real 0m1.445s
user 0m0.018s
sys  0m0.040s
看的出它的"效果"驚人!這對於 developer 的工作有相當大的幫助。並且, GVM 工具也支援安裝 GroovyServ,維護上相當方便。

ps.
停用 GroovyServ 的指令:
groovyserver -k

2013年8月19日

Upgrade subversion 至 v1.7.11

繼上篇解決 OSX 10.6 中安裝 SVN 與 Git 的 zlib 問題;為 upgrade subversion 至 v1.7.x 好讓 GGTS/Subclipse v1.8 開發工具所使用,進行下列指令的處置:
cd /usr/local/Library/Formula/
brew update
brew versions subversion
git checkout 0060dc3 /usr/local/Library/Formula/subversion.rb
卻發生無法安裝情形:
處理的方法是改安裝 v1.7.11:
brew tap homebrew/versions
brew install --universal --java subversion17
這樣子只要再檢查 /Library/Java/Extensions 下有沒有相關的 symbolic link:
隨即開啟 GGTS 設定: [Preferences/Team/SVN] 下的 [SVN interface] 至 "JavaHL (JNI) 1.7.11 (r1503888)" 即可。

2013年8月7日

Java 的檔案傳輸

說到網路通訊,在一般 Java 的實作上多半會兩種方式: HTTP 或 RMI (當然也可寫個 socket server / client)。無論坊間的教育中心或書籍,都會有基本的範例;而且現今的 Internet 中也有很多成熟的 sample code (只要問對谷歌大神)。

那檔案傳輸呢:

一般提到 Java I/O 時,很多的 software developer 並不會對它陌生;遇到 HTTP 的檔案傳輸可使用如 Apache HTTPClient 這樣子的 package,以 multi-part 方式 (MultipartEntity) 來傳輸。

但個人有遇過 "咬" 住的測試經驗。於是乎搬出 PipedInputStream / PipedOutputStream 再加上啟用一個 Thread 來處理,就可以解決這個問題了。以 Groovy 為例:
...
def InputStream pipeOutput(Closure write) {
 def output = new PipedOutputStream()
 def input = new PipedInputStream(output)

 Thread.start {
  try{
   write(output)
   output.flush()

  } finally {
   try { output?.close() } catch (e) {/*nothing to do*/}
  }
 }
 return input
}
...
...
def ctn = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE)
ctn.addPart("zipFile",
 new InputStreamBody(
  pipeOutput { output ->
   Thread.currentThread().sleep(1000)
   inFile = new FileInputStream(fileName)
     output << inFile
  }
  ,'application/x-gzip'
  ,'test.gz'
 )
)
...
...
// HttpClient的處理 <略>
...
@@ (暈了嗎?)
那 RMI 呢? (想到就頭大?)

還好有 RMIIO 這個好心的 package (是 LGPL 哦,感動吧!感謝作者)
它的優點,就是如同它的說明所描述:  makes it as simple as possible to stream large amounts of data
我個人使用它的心得是,沒有 "咬" 住的情形。而且當初看上它的原因是 client code 與 server code 之間,不需要做 nofity 與 ack 這樣多餘的機制來傳檔與送回接到檔案的訊息:
A --- send ---> B
A <--- ack --- B

只要控制是否 throw RemoteException 以及 try / catch 這個 exception 即可。以 Java code 為例:
// 傳送端
// 用壓縮的 InputStream
try {
  ...
  RemoteInputStream remoteIs = exporter.export(new GZIPRemoteInputStream(fileInputStream));
  ...
  remoteObject.receiveData(remoteIs);
  ...
} catch ...
...
// 接收端
public void receiveData(RemoteInputStream remoteIs) throws RemoteException {
  ...
  InputStream is = RemoteInputStreamClient.wrap(remoteIs);
  ...
  if (somethingWrong) throw new RemoteException("some message");
  ...
  // InputStream / OutputStream 後續處理 
  ...
}