2016年12月27日 星期二

使用 Java 連上 PTT

因為需要嘗試透過 Telnet 登入 PTT,雖然理論上覺得 PTT 的 Android App 這麼多,應該不會找不到可以引用的 Open Source
但實際找了,好像還真的找不太到 @@
最後是參考了 Github 上的一個開源專案 [1],擷取了其中連線和取得畫面的部份作為這次的實驗~。

2016年12月23日 星期五

Maven BOM (bill of materials)

在比較大型的專案中使用 Maven,有頗高的機率會遇到版本衝突的問題
例如 project A 使用了 guava 的某個 15 版才開始有的功能,而 project B 則是引用了 guava v14
接著有一個新的專案 project C,必須要同時引用 project A 和 project B,這時會發生什麼事呢?
有可能會造成最後打包出來的專案,裡面實際上被打包的是 guava v14
因而導致了在執行時,執行到 project A 的程式碼,就遇到 class/method not found 之類的錯誤訊息。

在 Maven 中,針對這個問題有一些基礎的解法 [1]
當同樣的套件被重複引用時,Maven 的基礎規則是誰先寫就看誰
但畢竟在遇到某些動態載入之類的情境時,並不是那麼容易可以決定誰先寫
更何況遇到的如果是 guava 這種被大量引用的函式庫,其實我們不見得能夠清楚地知道到底有哪些函式庫用了它。
因此,在基礎的解法之上的下個階段,就是利用 dependencyManagement 來指派版本了。

具體來說,dependencyManagement 的指派好像有兩種用法,一種是建立父子關係,另一種則是 BOM
詳細的範例其實都可以參考官方文件 [1],這裡紀錄的是 BOM。

2016年12月21日 星期三

變更已經啟動的 Container 的 Port Mapping

在使用 Docker 時,有時會遇到當初開啟 Container 時沒有預期到的 Port Mapping 需求
例如我有個服務本來是把 443 port 轉到 11111 port,但因為想要做 SSL 測試,而測試網站只支援 443 port
因此至少在測試階段需要把服務開回到 443 port 上。

一般查到的作法不外乎是把既有的 Container 做成 image,然後重開一個新的
不過發現另一個方法,可以透過改設定的方式,在不需要重開 Container 的情況下就達到變更的目的。

2016年11月17日 星期四

URL Encode

在寫 RESTful API 的測試案例時,遇到需要在 URL 路徑上寫空白的問題
如果使用 URLEncoder,空白會被編碼成 +,然後在 Jersey 端 + 並不會被編回空白。
簡單查了一下,實際上這個問題是誤用,URLEncoder 事實上是用在 URL 參數的工具
而把空白編成 + 則是 application/x-www-form-urlencoded 的標準作法。

因此,真正的問題在於不該使用 URLEncoder 去編碼 URL 路徑
但如果是片段的 URL,又沒辦法直接使用 new URI() 的樣子~
可以參考 [2] 的回應,使用 new URI(null, xxx, null).toASCIIString()。

另外,如果某個 Path 變數需要帶有 /,則可以手動用 String.replace() 方法,把 / 置換成 %2f"。
至少這樣在 Jersey 上是不會錯,但不保證所有的情境都可以這樣就是了 [3]。

參考資料
  1. Path parameters with a plus (+) sign is not decoded
  2. How to get absolute path with proper character encoding in Java?
  3. Is a slash (“/”) equivalent to an encoded slash (“%2F”) in the path portion of an HTTP URL

2016年11月11日 星期五

在 Windows 上變更 Maven 預設路徑

Maven 預設會在 ${user.home}/.m2/repository 這個路徑內存放所有下載回來的函式庫
不過如果電腦是用 SSD 當系統碟時,就會覺得這樣有點討厭 XD
想要更改路徑的話,只需要在 Maven 的設定檔上加上 localRepository 標籤,指定新的路徑即可。

例如在 ${user.home}/.m2/settings.xml 裡寫上以下的內容,即可把 Maven 存放函式庫的位置移到 D:\maven 裡。

<settings>
	<localRepository>D:\maven</localRepository>
</settings>
參考資料
  1. Configuring Maven

2016年10月20日 星期四

在全新的 Tomcat 8 設定 HTTPS

前面的文章成功在 Apache2 設定 HTTPS 之後,接著要在 Tomcat 8 上也設定 HTTPS。
環境一樣是要用全新的 Tomcat,因此流程也會包含環境建置。
而金鑰跟憑證的部份跟前面一樣,由 Godaddy 給予的兩個檔案:fe461f1ba212ab7.crt 和 gd_bundle-g2-g1.crt
以及事先產生好的金鑰檔 my-private-key.key。

Error 'handshake alert: unrecognized_name'

參考資料
  1. SSL handshake alert: unrecognized_name error since upgrade to Java 1.7.0
  2. Error 'handshake alert: unrecognized_name' when setting up application links after upgrading Confluence

在全新的 Apache 2.4 設定 HTTPS

在完成跟 GoDaddy 申請憑證之後,Godaddy 網站上可以取得兩個 CRT 檔
我這邊拿到的,一個是命名很像亂碼的 fe461f1ba212ab7.crt 檔案,另一個則是 gd_bundle-g2-g1.crt。
fe461f1ba212ab7.crt 這個檔案是 SSL Certificate File,而 gd_bundle-g2-g1.crt 則是 SSL Certificate Chain File
加上申請憑證前,我們需要自行先產生的金鑰,假設檔名是 my-private-key.key
總共有三個檔案,就可以完成 Apache 2.4 的 HTTPS 設定了。

2016年10月18日 星期二

在 Docker 中安裝 Bugzilla

這篇是簡單紀錄 Bugzilla 的安裝流程,流程中會以 Docker 1.12.0 來部署需要的服務。
Bugzilla 官方提供的安裝文件可以參考 [1]。

2016年10月9日 星期日

GTX650 穩定性問題

本來在玩遊戲時,電腦會頻繁地跳出遊戲畫面,或者是遊戲程式崩潰等等
原先以為問題顯示器驅動程式停止回應
但即使在依照那些方式做了調整後,依然在某些遊戲中會遇到跳出的問題(只是不會有驅動程式停止回應的訊息)
後來又繼續查了一段時間後,發現 [1] 這篇文章
就照著文章最後說的,去調整 PCI-E 的版本,從 PCI-E 3.0 改為 PCI-E 2.0,就….好像是完全好了…..。
不確定結果問題是 EVGA 的顯示卡對 PCI-E 3.0 支援有異常,還是特定一群主機板晶片組對 PCI-E 3.0 支援都有問題
總之應該不用考慮要換顯卡了….。

PS. 我的主機板晶片是 H87M。

參考資料
  1. GTX 650 stability problem

2016年9月10日 星期六

Gson 基礎使用:序列化與反序列化時,使用不同的名稱

在利用 Gson 做自動序列化與反序列化時,有時會遇到有點特殊的需求
就是序列化與反序列化時,想要使用不同的名稱。
實務上比較直覺的狀況是,某個物件是要從資料庫取出的,然後要將物件內容透過 JSON 格式輸出給使用者
但是又不希望使用者可以直接從 JSON 格式看見資料庫的結構,因此會嘗試至少把名字換掉 XD
(雖然這個例子看起來好像只是鴕鳥心態就是了 XD)

2016年9月7日 星期三

自定義 Logback 的 Encoder

想要試著自定義一個可以產出 JSON 格式的 log
雖然之前已經有 PO 過 logstash 提供的 Encoder,就可以達到把 log 輸出成 JSON 的目的
不過基於某些無聊的理由,還是想要自己寫看看 XD。

2016年9月6日 星期二

SLF4J 與 Logback 的運作流程

最近因為工作需要,開始在研究如何自定義 logback 的 Appender
不過在開始嘗試實作之前,因為想要知道整個 slf4j 到 logback 等的整個執行流程為何
因此就做了這篇的簡單的研究。

2016年8月24日 星期三

Docker container 的實體路徑

Docker 創造出來的 container,各自的實體路徑是在以下的位置:

/var/lib/docker/devicemapper/mnt/<container id>/rootfs/
參考資料
  1. Exploring Docker container's file system

Apache 2 SSL 的 Passphrase 問題

在 Apache 2 裡,如果要使用有被 Passphrase 保護的 key 給 SSL 使用
必須在某處提供 SSL 的 Passphrase 才能讓 Apache 正常啟動。

一般內建的方法是使用 builtin,也就是 Apache 啟動時會直接詢問使用者
其他方法則是可以把 Passphrase 寫在某個檔案裡,要 Apache 啟動時去讀取。

而寫設定的地方,在我的 container 中是放在 /etc/apache2/mods-enabled/ssl.conf 裡。

如果是不想那麼麻煩地處理 Passphrase 問題,想把他從金鑰中移掉
則可以參考 [2] 的方法,只需要指定輸入和輸出的金鑰檔名,然後輸入 Passphrase
就可以重製出一個不需要 Passphrase 的金鑰了。

以 RSA 的金鑰來說,指令如下:

openssl rsa -in /path/to/your/rsakey.key -out /path/to/your/rsa.nocrypt.key

參考資料
  1. Apache Requires SSL / Passphrase
  2. Remove the passphrase from an existing OpenSSL key file

2016年7月25日 星期一

Amazon Beanstalk 的應用程式位置

隨筆紀錄,如果把 Java 程式部署到 Beanstalk 上
預設在 Beanstalk 的路徑會是 /var/app/current/application.jar。

2016年7月4日 星期一

透過 Gson 輸出 pretty print 的 JSON

當使用 Gson 來解析 JSON 格式時,如果需要讓輸出的 JSON 以 pretty print 格式輸出
可以利用簡單的小工具達成這個目的。

Gson gsonBuilder = new GsonBuilder().setPrettyPrinting().create();
gsonBuilder.toJson(....);

不過 Gson 的這個工具,預設會自動做 HTML 跳脫,因此特殊符號都會自動被置換成 Unicode 表示形式
如果想要關掉 HTML 跳脫,可以使用 .disableHtmlEscaping() 方法。

Gson gsonBuilder = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
gsonBuilder.toJson(....);

2016年7月2日 星期六

對 Jersey 製作的 RESTful API 做單元測試(二):啟用 Servlet

Jersey 中使用 Jersey Test Framework 做測試時
如果遇到需要使用 Servlet 的狀況,例如使用了 @Context HttpServletRequest request
可能就會注意到,HttpServletRequest 這類應該要自動被注入的東西,在測試時都沒有被注入
因此會發生像是 NullPointerException 等等的錯誤。

2016年6月20日 星期一

在 Java 中解析、表達與計算日期時間(二):JSR-310 概述

原本在 Java 7 和更之前的版本中,因為 Java 原生並沒有好的時間類別
因此比較合適的方式是使用 Joda-Time 這個套件,用來表示日期與時間。
不過在 Java 8 當中釋出了 JSR-310,也就是 java.time 套件之後,狀況就不同了
Joda-Time 官方網站中也說明了,如果使用 Java 8 以上版本,應轉移至 JSR-310。

Joda-Time is the de facto standard date and time library for Java prior to Java SE 8. Users are now asked to migrate to java.time (JSR-310).

2016年6月19日 星期日

在 Java 中解析、表達與計算日期時間(一):時間系統與曆法

對大多數人(包括我)來說,大概都不會覺得日期時間有什麼特別的
在參加之前的 Java TWO 以前,其實我也沒有認真看待過這個東西,一直到在 Java TWO 上聽到良葛格談到這個議題
才知道~其實背後隱藏了許多魔鬼,導致這個議題事實上是個相當複雜的問題。

在開始研究如何正確地寫日期與時間相關的程式之前,先了解一下何謂時間、以及時間和曆法的關係為何。

2016年6月16日 星期四

使用 JAX-RS 2 做 HTTP Response 的壓縮

因為前陣子看了一些 RESTful API 的最佳實例(連結可以參考這裡
裡面有提到好的 RESTful API 應該要支援 GZIP 壓縮,對伺服器端或者客戶端都有好處
因此開始在實作 RESTful API 時,就搜尋了一下,Jersey 上應該如何正確地支援 GZIP 壓縮。

對於「正確地支援 GZIP 壓縮」這個問題,當然最簡單的作法,就是每個 RESTful API 都各自把輸出的東西都呼叫 GZIP 壓縮
然後把壓縮好的結果丟去 Response,並且適當地加上 HTTP Header 即可。
但我覺得這種作法應該不是最好的作法,應該有更好的方式可以讓 Jersey 自動幫每個 Response 都做好這些事。
在 Jersey 上,這件事情最適合的方式就是透過 Interceptors 來實作了。

2016年6月15日 星期三

對 Jersey 製作的 RESTful API 做單元測試(一)

在比較完整的專案中,一般都會至少要包含自動化的單元測試
不過 Application 還好,如果是 RESTful API 的話,應該要怎麼測試呢?

原先我自己的想法是使用 JUnit,然後可能是使用內嵌式的 Jetty
讓測試程式執行時,自動打開一台本地端的 Jetty、把專案佈署上去後開始執行測試。
但既有找到的方法(例如 [1]) 感覺整合性都不太高…。
最後想說,也許其實有更簡易的方式,於是變更了關鍵字之後,發現…真的有 XD。
Jersey 原來本身就有涵蓋了對應的測試架構了。

叢集環境的 logging(三):以 JSON 格式輸出 log

在把叢集中的每個 Application 的 log 都集中起來以後,下一個遇到的問題就是如何分析?
收集起來的 log 數量通常不小,而且各個不同節點的 log 全混在一起
要如何有效率一點地解析他們呢?

實務上,比較容易想像的方式大概就是把 log 導到某個能夠做 log 分析的系統上
例如 ELK 架構(Elasticsearch + Logstash + Kibana)。
不過要讓 Logstash 能夠簡單地把集中起來的 log 全部帶走,最好還是能讓 log 都以 JSON 格式輸出
這樣在 Logstash 那邊寫設定檔時,會比較簡單。

2016年6月7日 星期二

叢集環境的 logging(二):辨識集中化 log 的來源

前篇文章中,利用了 logback 的 SocketAppender 和 Receiver 功能,將不同來源的 logs 集中到一個地方
但在沒有特別設計的情況下,其實我們通常會分不出來哪個 log 來自哪裡。
不過這個問題在 logback 裡已經被考慮過了,可以利用 Mapped Diagnostic Context [1-2] 來實現。

叢集環境的 logging(一):透過 slf4j + logback 集中化 log

在叢集環境中,應用程式往往會同時存在在很多個節點上
每個節點的 log 都各自輸出到自己的 console,或者可能輸出成某個檔案,但都四散在每個應用程式自己的節點上。
實務上如果想要觀察 log,通常會希望最起碼 log 可以集中到某個地方
這個需求,如果是使用 logback 作為 logging framework 時,可以透過使用 SocketAppender 和 Receiver 來達成。

2016年6月6日 星期一

使用 Maven 建立 Jersey 專案

當想要新建一個使用 Jersey 的 RESTful 的專案時,可以利用 Maven 直接產生範例 [1]

mvn archetype:generate -DarchetypeArtifactId=jersey-quickstart-grizzly2 \
-DarchetypeGroupId=org.glassfish.jersey.archetypes -DinteractiveMode=false \
-DgroupId=com.example -DartifactId=simple-service -Dpackage=com.example \
-DarchetypeVersion=2.23
從上述的官方範例中,執行後會自動產生 groupId 為 com.example、artifactId 是 simple-service
並且會先建好 com.example 這個 package 的檔案(包含 src 目錄以及 pom.xml)
之後以 eclipse 來說就直接 import 到 eclipse 裡面,就可以開始增加自己需要的東西了。

另外紀錄一件小事,因為最近在 Windows 上習慣用 PowerShell,但上述的語法卻一直不能使用
研究了一段時間之後才發現,錯誤的並不是語法本身,而是在 PowerShell 上必須加上引號 [2]
例如:

mvn archetype:generate "-DarchetypeArtifactId=jersey-quickstart-grizzly2" \
"-DarchetypeGroupId=org.glassfish.jersey.archetypes" "-DinteractiveMode=false" \
"-DgroupId=com.example" "-DartifactId=simple-service" "-Dpackage=com.example" \
"-DarchetypeVersion=2.23"

參考資料:

  1. Jersey - Chapter 1. Getting Started
  2. Maven 3: Maven in 5 minutes “mvn archetype:generate…” command NOT WORKING

2016年6月2日 星期四

推薦的 RESTful API 最佳實踐

想要設計好的 RESTful API,所以花了些時間找了一些文章看
(其實也只不過是去 Google「rest api design best practice」而已)
找到兩篇看完覺得我被說服了的文章
推薦有想要好好設計 RESTful API 的朋友可以參考看看。

參考資料:
  1. Best Practices for Designing a Pragmatic RESTful API
  2. RESTful Service Best Practices - Recommendations for Creating Web Services (PDF) 

FortiGate 的虛擬 IP 設定

參考資料:
  1. Creating a Fortigate Virtual IP – External to internal Port Forwarding

2016年5月31日 星期二

ISO-8601 字串轉型成 Calendar

ISO 8601 是標準的日期時間表示法 [1],在一些有遵守標準的網站上,很容易看到這種以表示法表示的時間。
在 Java 裡,有一些不算困難的方法,可以把 ISO-8601 表示法的文字轉成對應的 Epoch Time
然後當然因為有了 Epoch Time,就可以進一步轉成 Calendar 或者 Date 等其他日期相關的類別。

2016年5月21日 星期六

(書籤) 清理 Ubuntu 的 /boot 磁區

其實在一般情況下,使用 autoclean 就可以自動清除不需要的 Kernel 了。
apt-get autoclean

參考資料:
  1. /boot partition is full

2016年5月19日 星期四

使用 JUnit 測試 private method

關於在 Unit Test 時,private method 到底是否應該測試的問題
應該是一個社群持續爭論中的問題~
相關的說法有部份可以參考看看 [1],這裡先跳過這個問題不管。
假設目標是要測試 private method,實務上可以利用 Reflection API 來達成 [2-3]。

2016年5月5日 星期四

檢查物件型態

一般在 Java 中,會用 instanceof 來檢查物件的型態
不過在對於 primitive type 時,無法使用這個檢查
另外當類別只能在執行期間才會知道的情況下,也沒辦法使用 instanceof
這時可以使用類別的 isAssignableFrom() 或者 isInstanceOf() 來檢查。

2016年5月2日 星期一

AWS DynamoDB SDK v2 基礎使用(一):基本認知

DynamoDB 是 Amazon 提供的 NoSQL 資料庫
不過就我最近使用的感覺,其實我覺得它比較像是「有 RDBMS 靈魂的 NoSQL」
換言之,我覺得它其實是個 RDBMS,只是稍微支援了一點 NoSQL 的功能而已。

關於 DynamoDB 的簡介就不細談了,網路上大概可以查到不少
主要想紀錄的是如何使用 DynamoDB 的 Java SDK。
陸續找了不少資料後,我覺得 DynamoDB 的文件 [1] 真是相當差勁。
官方文件給的範例非常地簡略,對於稍微複雜一點的指令就沒有說明該如何實作
Google 往往會找到許多過去的部落格文章、或者甚至是官方的部落格
然後會發現同一件事情有好幾種不同的實作方法,估計大概是新舊的 API 的差別
每種實作方法似乎都有一些優點跟缺點,對使用者來說雖然可以依照自己的需求做選擇
但對於多數剛開始使用 API 的開發者來說,可能只會跟我一樣頻頻想說「WTF」。

2016年5月1日 星期日

顯示器驅動程式停止回應

不知道從何時開始,電腦開啟某些遊戲一段時間就會一片黑
然後跳回桌面,右下角會顯示「顯示器驅動程式停止回應」。
這時遊戲大概畫面都會有點問題,有時這個問題會一直連續發生,最後會變成藍白畫面。
最初以為是驅動程式不穩定,不過換了很多個版本還是都沒有改善
今天又花了不少時間在找這個問題,不過找到國外的論壇的討論 [1]
其實只要移除掉 Windows 的 KB2685811 這個更新 [2] 就好了!

目前還沒有嚴謹地做過測試,不過至少我現在用 EVGA GTX650 的顯示卡
作業系統是 Windows 7,驅動程式降版到 310.90 WHQL,然後移除 KB2685811 更新
玩 Steam 版的俠客風雲傳可以成功通過最初的對話以及教學戰鬥了 XD。

2016-05-05 更新:實際上還是會出現驅動程式停止回應跟當機的狀況,但已經從原本十分鐘內掛掉,變成可以連續玩幾個小時後,才有可能掛掉。不過再加上 [3] 更改 TDR 以後就沒有再發生了。
2016-07-04 更新:310.90 WHQL 改玩 Steam 的信長之野望時還是一直出問題,後來用 DDU 移除重灌成 337.88 WHQL,目前看起來比 310.90 WHQL 穩定。

PS. 不過這個方法應該不適用  Windows 8,因為 KB2685811 這個更新本來就是給 Windows 8 的更新。

參考資料:
  1. Nvidia - Display driver has stopped responding and has recovered error
  2. Windows Vista、Windows Server 2008、Windows 7 及 Windows Server 2008 R2 的核心模式驅動程式架構 1.11 版更新
  3. Graphics driver stopped responding and has recovered....TDR fix
  4. "Display driver stopped responding and has recovered" error in Windows 7 or Windows Vista

2016年4月27日 星期三

Java 的基本物件複製

如果當物件的成員並沒有包含特殊的物件時,可以直接使用 super.clone() 方法自動做物件的複製。
public class Test implements Cloneable {
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

不過如果物件成員有包含比較複雜的成員
例如成員有包含另外一個也內含成員的物件的話,會有稍微複雜一點的狀況
可以參考 [1] 去實作。

參考資料:
  1. Java複製(Clone)的應用

2016年4月19日 星期二

在 FortiGate 上啟用進階 DHCP 設定

可以參考 [1] 的作法,效果包括可以指定 DHCP 的 lease time
以及 DHCP 的靜態 IP 也可以在進階設定中調整。

參考資料:
  1. Technical Note: How to enable advanced DHCP options on FortiGate v5.2

2016年3月24日 星期四

自行架設 Wiki 引擎(一)補充:手動以 HTTPS 安裝 Foswiki

之前文章「自行架設 Wiki 引擎(一)補充:手動安裝 Foswiki」中
主要是描述以手動安裝的方式,將 Foswiki 整套安裝起來
其中會這麼做,主要是因為 Foswiki 的 Debian 套件很久沒人更新了。

2016年3月8日 星期二

使用 Selenium 與 HtmlUnit 時,忽略 script error 和 http statuscode 的方法

在 Java 上要呼叫 Selenium,並且指定使用 HtmlUnit 時,在某些網站可能會遇到兩種問題:

  1. 網站的 JavaScript 在解析過程有錯誤。
  2. 網頁本身失連、或者網頁內的任一連結(包含 JavaScript 檔、CSS 檔、圖片等外部連結)失連。
 在上面這兩種問題之下,HtmlUnit 預設都會直接丟 Exception,導致沒有辦法繼續運作。

2016年2月17日 星期三

HttpClient 在重複不斷存取相同的 URL 時持續 timeout 的問題

做個記錄,寫了一段會一直重複下載同樣一群 RSS 網頁的程式碼
在測試時發現寫的程式碼第一次執行時正常、第二次執行到一半開始一直 timeout
但關掉程式再重新啟動時,第一次又恢復正常,然後一樣第二次差不多地方開始一直 timeout
存取其他不同網址的網頁時則好像沒問題~
最後發現是因為程式碼在最後忘了把 CloseableHttpResponse 關掉(即呼叫 close() 函式)。

2016年1月11日 星期一

使用 Maven 打包 jar,並將引用的 dependencies 一併打包

在匯出 jar 時,如果是用在 Spark 或 Storm 這類平台
就沒有簡短的途徑,一定要把 jar 引用到的所有第三方函式庫,一併全打包進 jar 裡
在 Maven 中可以透過設定幾個 build 參數來達成。

在 Ubuntu 14.04 安裝 MongoDB 3.2:使用 WiredTiger 儲存引擎

這篇主要是嘗試在 Ubuntu 14.04 的環境中,使用 6 台主機建置一個基於 WiredTiger 引擎的 MongoDB 叢集。
其中會以兩台主機建成 Shard 的 replica set、以三台主機建成 Config 的 replica set,並以一台主機作為 Mongos