星期五, 7月 26, 2013

Linux 上 Tomcat 以一般User身份執行

由於前陣子爆發 Struts2.3.15(含)之前的版本有遠程可入侵漏洞。
維護的網站也中獎了。

除了升級 struts2 到 2.3.15.1 外,也研究了一下該如何讓 Tomcat 不以 ROOT 身份執行。

紀錄一下步驟:
1. 由於 1024 以下的 port 只能以 root 身份執行, 因此將 tomcat 啟動 port 設為 8080, 8443
2. add tomcat user / group
3. 修改相關目錄的權限, 擁有者
4. 修改 /etc/init.d/tomcat 直接執行 startup.sh 並以指定身份執行 (su -c xxx)
5. 透過 xinetd 來設定 80 轉到 8080, 443 轉到 8443 的模式來使用。

還有查到可使用 iptables 的方式,是 linux 核心內建,效能更好。
但較複雜,因此若有效能問題再來調整。

參考了以下文件:
http://ruleoftech.com/2009/redirecting-http-and-https-traffic-to-tomcats-ports
http://www.nsfocus.net/index.php?act=magazine&do=view&mid=1954
http://mushme.iteye.com/blog/1636467
http://blog.sina.com.cn/s/blog_660bfc2801018w4s.html

星期四, 4月 11, 2013

MS JDBC Driver + Proxool

前陣子碰到一個好玩的問題。

狀況:透過 hibernate + proxool + jtds 使用 SSO 方式連 SQL Server 時好時壞。常常出現 SQL Error: 0, SQLState: 08S01 無法連線狀況。
 一聽到此狀況,就先給了建議,改採用 MS 之 JDBC Driver 試試。
後來回報是改採用 MS 的 Driver 情況反而更慘。錯誤就是都無法連線。

所以依此測試結果判斷,就去查看 source code。
結果發現在使用 hibernate 的 session 等處理都是透過 static 變數。
這樣當然會有問題,因 multi-thread 環境下,可能某 thread 已經關閉 session。另一個 thread 還在使用,就會發生問題。

因此請同事考慮 multi-thread 之情況,調整到好。

調整到好之後,問題依舊。

因此再建議改用最陽春的解法,直接透過 JDBC 而不透過 hibernate。
沒想到問題更嚴重了。

但同事後來又試了將 hibernate 由 3.2 換到 3.6 之後,竟然發現ok了。

所以歸咎於是 hibernate 的問題,但此結論實在不能說服我。
且此專案已經近尾聲,更換此 jar 檔等於整個專案都需要重測。
於是,就直接去客戶端實地查看問題。

再測試一遍,發現,hibernate 是有透過 proxool 連 DB,雖然有時會錯,但有連上後,因 Connection Pool 會保留此連線,因此後續就正常。
所以純 JDBC 版本也透過 proxool 來連,情況也與使用 hibernate 情況一致。

但只要換成新版 hibernate,就都正常。
心裡在想,會不會 hibernate 有自己重試連不上就重連機制啊。否則這實在無法解釋。
於是下載了 hibernate source code 來追。不論怎麼追就是無此機制。

但只要無法解釋,心理就會覺得不踏實,因此多試了幾次。
發現,透過新版 hibernate 還是會時好時壞,只是壞的機率低很多。
那就有可能了,可能新版 hibernate 做了最佳化,讓問題出現的機率低很多。
但這不代表問題解決了。

由於只要透過 SQL 認證來連就都不會出錯,改用 Windows SSO 認證才會。
且都是一開始連線就會出錯,還是感覺換成 MS JDBC Driver 應該會比較好。
都是 MS 的產品,應該穩很多吧。

果然換回舊版 hibernate,使用純 JDBC 模式連線,就算不用 Proxool 也非常穩定。
那之前說使用 MS JDBC 不行又是什麼一回事。
原來當時是使用 hibernate 的模式。

再換成 hibernate 模式後果然出錯。出現:
Caused by: java.lang.SecurityException: class "com.microsoft.sqlserver.jdbc.ISQLServerConnection$$FastClassByProxool$$2b8cf6af"'s signer information does not match signer information of other classes in the same package

看到此錯誤,其實就很明顯了。
這是因為 MS 之 JDBC Driver 的 JAR 檔有 sign 過。但卻不符合。
而此是透過 Proxool 才會有此錯誤。
當時建議兩個方案,改採 hibernate 本身陽春之 Connection Pool,或根本不要使用 Connection Pool。果然一換就可正常運作。

另一個方案就是把 MS JDBC Jar 檔內之 sign information 檔刪除。
最後 PM 決定不要動 JAR 檔,因此改採 hibernate 本身之 Connection Pool 來解決。

而在事後,我自己測試時,即將 MS JDBC Jar 檔內之 sign info 檔刪除。
確實透過 Proxool 也可正常連線。

至於為何 proxool 會有此問題呢? 追究其 exception dump,發現其是透過 cglib 去動態 load 物件。所以推測此為 Java 本身的限制,若是動態去 load 物件。而其物件之 Jar 檔是有 sign 過的。則必須驗證其正確性。

那為何當初換 MS JDBC Driver 時出錯沒有找出此問題呢?
因為當時 catch 到 exception 時,輸出到 Logging 沒有輸出 exception stack。
都只看到一行連線錯誤的訊息。錯失提早解決問題的時機。

總結:

  1. 使用 jtds 用 windows 認證 SSO 登入方式連 SQL Server 2005 會時好時壞。連 SQL Server 2008 則很穩定。此結論為推測,因未排除只連 SQL Server 2000 會不會正常。此案子是同時有連 2005 與 2008。但連 2008 都很正常。因此才做此推測。
  2. MS JDBC JAR 為何 signer 無法 match 還沒研究。
  3. 使用 Proxool 連 MS JDBC,須將 JAR 檔內之 sign info 檔案刪除。
  4. 不該疏忽任何 exception stack 輸出。
  5. 對無法解釋的行為,不能妄下結論。





星期三, 4月 10, 2013

Sublime Text 2

最近摸了 Mac,所以會希望找一些可以跨平台的軟體。Mac 與 Windows 都可用的。
經同事介紹了 Sublime Text 2 這套好用的編輯器。
紀錄一些備忘。

Sublime Package Control --> http://wbond.net/sublime_packages/package_control

裝好後,按下 Ctrl + Shift + P 輸入 Install Package 進入 Package 列表安裝

VI mode
  1. Select the Preferences/Settings - Default menu item
  2. Edit the ignored_packages setting, changing it from:
  3.            "ignored_packages": ["Vintage"]
      to:
           "ignored_packages": []
解決ANSI亂碼問題: https://github.com/seanliang/ConvertToUTF8


Xcode 4.6.1 use XVim

由於 Xcode 內的快速鍵需要重新熟悉,且查無還蠻常用的在下一行插入空行的功能。
加上 mac book pro 的鍵盤少了 Home / End 按鍵直接按。頗麻煩。
與其要重新熟悉,不如找一套可以跨平台通吃的快速鍵。
最後找到 Eclipse 與 Xcode 都分別有 Vim 的外掛可以裝。
再加上 Sublime Text 2 本身也支援 Vim 的快速鍵。
雖然已經非常久沒用 Vim,但再重新學起也比重學 Xcode 快速鍵值得。

Xcode 找到的就是 XVim 這套外掛了。

XVim (https://github.com/JugglerShu/XVim)

但此套需要開啟 Xcode 來自行編譯執行來安裝。
因目前也不熟 Xcode ,確實被此折騰了一下。

所以就把編譯發生的問題及解決紀錄下來:

1. "Cocoa/Cocoa.h file not found"
 ==> 需安裝 Command Line Tools 來解決 (https://discussions.apple.com/thread/4236895?start=0&tstart=0)

2. - (NSUInteger)getAddress:(unichar *)parsing:(unichar **)cmdLeft inWindow:(XVimWindow *)window
會出現 'parsing' used as the name of previous parameter rather than as part of the selector 錯誤。

原因出在此 method 第二個參數為暱名參數,在舊版 Xcode 不會出錯。但新版趨於嚴格因此報錯。
解決方法為 parsing 後面多加一個空白。
或是打開 project.pch 檔案加入一行:

#pragma clang diagnostic ignored "-Wmissing-selector-name"

(http://stackoverflow.com/questions/14579197/how-to-disable-new-xcode-4-6-warning-for-whole-project-used-as-the-name-of)

再解決以上兩點後即可 compile 並執行,最後重開 Xcode 即有 Vim 支援了。

HTTPServletRequest POST 取不到資料


最近碰到一個問題,透過 HttpClient POST XML 資料給 Servlet,會一直抓不到資料。
但若透過 REST-Console POST XML 資料給該 Servlet,該 Servlet 又抓得到資料。

問題確實很詭異。

追查到最後,發現是有一隻 filter,呼叫了 request.getParameter("xx") 原因造成。
那為何 request.getParameter 會造成此問題呢?

看看 API 怎麼說明:
If the parameter data was sent in the request body, such as occurs with an HTTP POST request, then reading the body directly via getInputStream() or getReader() can interfere with the execution of this method.

看來送出 POST 由於可能 Request 裡也會有參數,因此就會透過 getInputStream() 來讀取。
因此到該 Servlet 後,再去讀取時,就都抓不到資料了。

那可以解釋為何 HttpClient POST 會抓不到資料,但無法解釋為何透過 REST-Console 來 POST 就可以抓到資料。

最後,查看此兩者所送出之 Header。

HttpClient 會送出 Content-Type: application/x-www-form-urlencoded
而 REST-Console 會送出  Content-Type: application/xml

這就是原因所在了。

由於送出的 header 為 x-www-form-urlencoded。
代表其內容也為 parameter 的格式,自然 getParameter 就會去讀取 Body 內的值。

而 InputStream 讀完了,自然也再讀不出資料來了。

星期五, 3月 29, 2013

XMLBeans 使用經驗紀錄

最近因為客戶要求 OXM (Object/XML Mapping) 必需使用 XMLBeans 2.5。

在此紀錄其與 JAXB 之差異點:
1. JAXB 在輸出 Big5 XML 時,若遇到非 Big5 編碼,會轉為 Unicode 編碼,如菓 --> 菓 而 XMLBeans 碰到這情況會直接輸出 ?

2. 雖然 XSD 定義中指出要使用 default namespace 的方式,但輸出時卻輸出有 prefix 之 Tag 模式。
   解決方式為輸出前需設定 XmlOptions 之 setUseDefaultNamespace();

3. 字串會自動判斷是否轉 CDATA,這是什麼意思呢?
我們知道 XML 內的 Tag 內容若有特殊符號,例如 Tag 內容為 <b>ABC</b>,需以CDATA包起來。
  <Root>
    <Body><![CDATA[<b>ABC</b>]]></Body>
  </Root>

或是將特殊符號進行 escape,如下:
  <Root>
    <Body>&lt;b&gt;ABC&lt;/b&gt;</Body>
  </Root>

也就是說,上面兩份 XML 基本上是相等的,只差在可讀性。

而我們透過 XMLBeans 的 Java 物件轉換為 XML 時。
發現,當這類需要 escape 的字元超過 5 個。則輸出會變成 CDATA 模式。若沒超過 5 個,則為 escape 模式。

由於使用不同模式會造成後續程式處理有誤。因此得查出此問題的發生原因。
最後追到 XMLBeans 之 API 說明。

原來 XmlOptions 有兩組參數:CDataLengthThreshold 與 CDataEntityCountThreshold 預設值分別為 32 與 5。
其轉換邏輯為當資料長度大於 CDataLengthThreshold 且 跳脫字元數量超過 CDataEntityCountThreshold 時會轉換為 CDATA 模式。

而我們希望的是,一律使用 escape 模式,在追了 XmlBeans source code 之後,很可惜的是,除了可以使用 XmlOptions.useCDataBookmarks() 來強迫使用 CDATA 模式外,並無設定一律使用 escape 的方法,且這兩個參數也不得設為 -1, 0 來表示無限制。所以只能將這兩個參數設大一點以避免問題。

星期一, 2月 04, 2013

Mac 初體驗

今年,終於買下了兩年前一直想買的Mac電腦,最主要當然是想學習 iOS 的 app 開發。
已經太熟悉 Windows 系統。轉換到 Mac 又有一堆需要習慣的,還是得強迫自己去習慣,話說:工欲善其事,必先利其器。

以下就記錄一些碰到的問題備忘。

1. 切換輸入法:cmd + space
2. 輸入法狀態下,按下大寫鍵後即可暫時輸入英文。
3. 非編輯器之 page up / page down:fn + 上/下
4. 編輯器中 某行 Home / End:cmd + 左/右
5. 編輯器中 文件 開頭 / 結尾:cmd + 上/下
6. 編輯器中 page up / page down  fn + opt + 上/下
5. 中文之逗號句號等符號:shift + 半形之逗號句號等符號。
6. 關閉程式:cmd + Q
7. 關閉視窗:cmd + W
8. 截圖(整個螢幕):cmd + shift + 3
9. 截圖(滑鼠選取區域):cmd + shift + 4
10. 截圖(指定視窗):cmd + shift + 4 + enter
11. 顯示桌面:F11
12. 同一程式之不同畫面切換:cmd + `    (Tab 上方)
13. Safari / Chrome 查游標所在字典: cmd + control + D

最困擾且不滿的就是 page up / page down 及 home / end 會隨著應用程式的不同而不同。
但不脫 opt, cmd, fn + 上下左右的組合。

雖然離上手還有一段路要走,不過Apple電腦的使用者體驗讓我非常驚喜。

星期三, 1月 23, 2013

Nexus 7

由於尾牙抽到 Nexus7,這幾天使用的感想是,不愧是 Google 出馬的作品。在使用者體驗上有進步許多。在 Android 系統中,我想這一款已經是上等的平板了。

其完整整合 Google 眾多服務,且 Android 4.2 可支援多使用者切換環境。以平板這種會多人使用的屬性來說,此功能確實非常實用。

當然也把之前寫過的程式從 Play 中再下載來跑跑看,原本不預期可以撥放 Live 影片的功能,竟然可以執行了。由於後來程式已交由客戶自行維護,但看了改法,其實就把原本將WebView寫在程式內改成叫出 Chrome 執行網址。之前在 Galaxy Gio 上不行是因為沒裝 Flash。再次重裝跑跑看確實一樣不能跑。

但此次平板也沒裝 Flash,卻可撥放。可以看了反而心裡覺得納悶(驚喜!?),於是開啟 Chrome 執行含有 Flash 的網頁,確實也是不能執行。而 Android 支援的 media 也沒列出支援 adobe 之 f4m 格式。搜尋了 google,找到一些讓 firefox 可以跑 flash 的做法。折騰了一陣子,還是找不出原因或解釋。在沒另一款機器可供交叉比對驗證想法,也只能放棄了。
當然若要徹底解決,就是要將這 Live 影片改採用 Android 原生支援的格式。如rtsp, webm等。

對於 ASUS 與 Google 合作推出的這台平板,我想在 Android 界,會是很有競爭力的產品。

星期二, 1月 22, 2013

Amazon Web Services 初體驗

之前透過同事的介紹,認識了 AWS(Amazon Web Services)。

而前陣子剛好有機會好好的研究了一番,買了一本好書 AWS雲端企業實戰聖經:Amazon Web Services改造企業IT體質 

因之前幫朋友架設在戰XX的網站在去年下半年開始變得非常不穩定。要嘛常當機,要嘛硬碟有壞軌,重灌後請服務人員切換或是重啟,也常常搞錯且效率非常低落。

趁著小女兒剛出生,老婆回娘家坐月子,只有一個人的夜晚,趁這時機好好研究 AWS 並將網站整個移到 AWS上。一開始要轉換,朋友還很擔心說,網站放國外,有問題要打去哪解決。
我說這整台機器都已經虛擬化,可以直接在網頁上管理這些機器,包括開機關機重啟等等。
另外一個疑慮就是費用計算太複雜,但Amazon有提供第一年免費的方案,我們就選這方案,試跑後再看狀況。

結果,轉換到現在已經 3 個月了,有多穩定呢? 一直到現在都還沒掛點過,若不是要換版調設定,還不知可以多久才重啟。實在是太穩定了。

也趁此機會,才讓我對所謂的"雲端"有了非常非常深刻的感受。之前只認為所謂雲端,只是一般webapp,真的是井底之蛙啊。

當然此系統已經好幾年了,當初並非針對雲端架構來設計,所以只是用了 AWS 中的 EC2來使用。但對此系統目前用量來說,已是綽綽有餘了。

除了實際跑的 instance 外,也架設了一個備援的 instance(從裝好的instance做出images檔後還原而來),也設定排程每天自動備份DB,並上傳到網路上做異地備份。並實際做了一次切換的演練,順到一整個覺得管理這些機器真是太輕鬆了。(在戰XX, 這些動作浪費了我許多光陰啊。)

下一步,就是往雲端架構設計方向學習努力了...