星期三, 3月 13, 2019

取得 IBM HTTP Server KDB 密碼





前一陣子,有個客戶的 SSL 憑證到期了,想要更新憑證,卻忘了當時建立的密碼。這時候可能需要重新使用 IBM 的 iKeyMan 工具再建立一次 KDB 檔案。後來,我回顧一下 KDB 建立的過程似乎有建立一個 stash 檔案,這個檔案似乎就存著密碼。

在 IBM HTTP Server 的 Config 檔案中,針對這個 KDB 的存取並沒有再特別設定密碼。所以,可以假設 stash 內就存著密碼,而且 IBM HTTP Server 可以解開這組密碼。

於是,上網找了一下是否有還原的機制,後來果然發現了相關的文章,並且實際驗證一下。

1. 我在 CentOS 的環境下建立一個 stash_decrypt.pl 檔案,內容如下:

#!/usr/bin/perl
use strict;
die "Usage: $0 <stash file>n" if $#ARGV != 0;
my $file=$ARGV[0];
open(F,$file) || die "Can't open $file: $!";
my $stash;
read F,$stash,1024;
my @unstash=map { $_^0xf5 } unpack("C*",$stash);
foreach my $c (@unstash) {
 last if $c eq 0;
 printf "%c",$c;
}
printf "\n";
2. 將 KDB 的 key.sth 檔案複製到與 stash_decrypt.pl 目錄中
3. 修改 stash_decrypt.pl 的權限為可執行
4. 執行 ./stash_decrypt.pl key.sth



最後可以看到 key.sth 檔案的密碼內容。

[參考資料]
1. https://websphereapplicationservernotes.files.wordpress.com/2012/04/websphere-doctor-7-recover-kdb-password.pdf

星期六, 12月 22, 2018

IBM MobileFirst web resources encryption

使用 IBM MobileFirst 開發行動應用程式時可以利用 MobileFirst Platform CLI 工具針對撰寫的 HTML、CSS及JavaScript 進行加密的動作。

因為 IBM MobileFirst 的專案是基於 Cordova 的專案,所以如果將 Web Resources 進行加密代表著要利用 ipa 或是 apk 進行反組譯檢視內部程式碼的困難度就增加了。

依據 IBM 官方的建議,要針對 Web Resources 進行加密動作最佳的時機點是在於應用程式開發完畢準備部署時,因為如果我們在進行 Web Resources 加密工作後執行下列指令,Web Resources 就會被解除:

  • cordova prepare
  • cordova build
  • cordova run
  • cordova emulate
  • mfpdev app webupdate
  • mfpdev app preview
所以,如果在進行上述指令後,就必須重新進行一次 Web Resources 加密的工作。

進行 mfpdev app webencrypt 程序

1. 在進行 Web Resources 加密前,先執行下列指令
  • corodva prepare
  • mfpdev app webupdate
    以便將專案程式碼同步到最新的版本。
2. 執行 mfpdev app webencrypt 指令
3. 檢視 web resources 加密後的結果


如上圖所示,在 WWW 目錄中出現 resources.zip.001 是 web resources 加密後的結果。

[參考資料]


星期三, 4月 18, 2018

Apache Cordova - Introduction


在工作上碰 Cordova 已經有蠻長的一段時間,從他還叫做 PhoneGap 的時代就已經開始接觸,目前已經有許多的客戶使用這樣的方式進行 App 開發作業。當然,在很多部分這樣的開發模型是比不上原生 (Native) 的開發,再者會用這樣開發方式的業主大多是從做 Web 開始,想要有進一步延伸出來的管道。很多時候,開發人員除了要關注 App 端之外,也需要關注 Server 的狀況,時間久了就慢慢變成要同時處理 App 與 Backend Server 的人。

雖然,看似有蠻多的需求,而且很多專案其實都找不到人可以執行。再到天瓏找找有沒有這類相關的書籍,看起來也不多。網路上的社群也沒有非常熱絡,也有可能是需求太多了大家沒空討論吧!剛好,最近有一連串的需求要進行教育訓練教材的準備,就將這些內容在網路上註記下來。

Apache Cordova 是一個行動應用開發框架的開放原始碼專案,它讓程式開發人員可以使用 Web 技術 (HTML5 + CSS3 + JavaScript) 來進行跨平台行動應用程式的開發。透過 Apache Cordova 開發出來的應用程式,可打包至各個不同的應用平台 (iOS and Android)。Cordova 應用程式會使用各平台標準的 API 來存取設備相關資訊。



什麼時候適合使用 Cordova 來進行 App 開發?
  • 假如你想要將你的應用程式拓展到不同的行動應用平台 (例如,iOS and Android),但你又不想各自開發一次,那麼使用這樣的技術會是一個好的選項。
  • 假如你是個 Web 應用工程師想要將 Web 應用程式打包並部署到不同的行動應用平台,以發布行動應用程式。
  • 假如你是一個行動應用開發工程師,對於混合式開發 (Web + Native) 感興趣,並想要開發 Web 與 Native 的溝通介面的話,可以嘗試 Cordova Plugin 的開發

下圖是 Apache Cordova 的架構圖:


Web App
在上圖中的 Web App 是我們所撰寫的程式碼,使用 HTML、JavaScript、CSS 等構成,預設的首頁是 index.html 在 HTML 內會定義參考的 CSS、JavaScript 及圖片等資源。


HTML Rendering Engine (WebView)
Cordova 應用程式透過 WebView (HTML Rendering Engine) 載入專案內的HTML 畫面作為 App 的使用者操作介面。

Cordova Plugin
Plugin 是 Cordova 裡非常重要的一部分,是 Web 與 Native 溝通的主要介面。我們可以透過 JavaScript 使用 Cordova Plugin 來存取底層的 Device API。
Apache Cordova 專案維護許多的 Plugin  可以在 Core Plugins 取得相關資訊,這些 Plugin 可以協助我們存取 Device 相關特性,例如電池、相機及通續錄等。除了這些官方的 Plugin 之外,我們也可以從 plugin search 或 npm 找到第三方的 Plugin 。

[參考資料]

星期五, 4月 13, 2018

Angular 5 Router Parameter

頁面的轉導以及相關參數的傳遞一直是 Web 應用程式發展的基礎,在 AngularJS 中,我們可以透過 Router 模組來定義各個頁面 (Component) 的繞送規則。然而,很多時候我們還需要將目前頁面上的參數往下一個頁面(Component)帶,才可以完成我們要做的工作。下列,說明如何在 AngularJS 裡進行參數傳遞的範例:

const routes: Routes = [
 { path: 'cmpa/:id', component: ComponentA },
 { path: 'cmpb/edit', component: ComponentB },
];
例如上述的 path/:id 即定義了一個 id 的變數,以變傳到 ComponentA 中。

2. 如何在 ComponentA 中接收 :id 參數?

import {ActivatedRoute} from "@angular/router";
.
.
.
constructor(private route: ActivatedRoute) {
    this.route.params.subscribe( params => console.log(params) );
}
使用 ActivateRoute 以取得相關參數資訊。在上述程式中,params 即為傳入的參數內容。


[參考資料]
1. https://codecraft.tv/courses/angular/routing/parameterised-routes/

星期三, 4月 11, 2018

IBM Application Center Push Notification of Application Update for Android and iOS


IBM Application Center Client 可以在應用程式更新時進行推播服務,告訴使用者已經有新版的應用程式上架,引導使用者進行下載新版的工作。

要完成這樣的功能,必須針對產品進行些許的設定,進一步說明如下:

1. Server 的設定
   IBM Application Center 可以安裝在 WebSphere Application Server、WebSphere Liberty Profile 以及 Tomcat 上。

   本文以 WebSphere Liberty 為例,需要在 server.xml 裡進行下列 JNDI 的設定:

Android:
<jndiEntry jndiName="ibm.appcenter.push.schedule.period.unit" value="hours" />
<jndiEntry jndiName="ibm.appcenter.push.schedule.period.amount value="2" />
<jndiEntry jndiName="ibm.appcenter.gcm.signature.googleapikey" value="AAAAX_7jiec:........" />
     其中 「ibm.appcenter.push.schedule.period.unit」的值建議使用 「hours」,避免伺服器過於頻繁檢查是否要進行推播,影響效能。(在測試的時候可以設定 seconds 以增進測試的效率)「ibm.appcenter.gcm.signature.googleapikey」可以使用 Firebase Cloud Message 上的 Server Key 來進行設定作業。

iOS 設定:
<jndiEntry jndiName="ibm.appcenter.apns.p12.certificate.location"  
     value='"D:/IBM/WebSphere/Liberty/usr/servers/MFPSrv2/PushNotification.p12"'/>

<jndiEntry jndiName="ibm.appcenter.apns.p12.certificate.password"  
     value='"yourpassword"'/>

<jndiEntry jndiName="ibm.appcenter.apns.p12.certificate.isDevelopmentCertificate"  
     value='"false"'/>
PushNotification.p12 憑證可以從 Apple Developer Account 針對包版的憑證進行 Push Notification 相關設定,設定完成後可以產生一個 .cer 檔案。將該 .cer 檔案匯入 MAC 上的「鑰匙圈存取」,再將其匯出成 p12 檔案,並設定密碼。

2. IBM App Center Client
   修改 CordovaAppCenterClient 內的 config.json 檔案內的「gcmProjectId」值。
   請建立一個 Firebase 專案,並且在專案設定頁面中進入 Cloud Messaging 的設定畫面,將「寄件者 id」抄出,並修改 gcmProjectId 值。

3. 進行測試
   接著我們可以上傳一個新的 ipa 或 apk 檔案,在上傳的時候記得將 Recommended 的 checkbox 打勾。接著,在一定時間內應該可以收到應用程式上版的推播通知。

4. 問題排解
   以上動作最好是在 App Center 上線前就完成,如果有人已經下載了 App 因相關推播內容設定值是錯誤的,例如:gcmProjectId 的值,那麼這時候可能就需要重置一下 App Center 的資料了。
 

參考資料:
[1] https://mobilefirstplatform.ibmcloud.com/tutorials/en/foundation/8.0/appcenter/push-notifications/
[2] https://www.ibm.com/support/knowledgecenter/en/SSHS8R_8.0.0/com.ibm.worklight.appcenter.doc/appcenter/t_ac_gcm_connect.html

星期一, 11月 20, 2017

Odd-e Certified ScrumMaster 心得分享 3 - 快速交付,小步快跑

快速交付,小步快跑


雖然,認識 Agile 或是 Scrum 已經有一段時間,自認對於快速交付及小步快跑也有一定程度的理解。但是,卻沒有像這次在課堂上感受這麼深刻。

在課堂上,我們進行了一個 workshop,規範了一個明確的產出物作為目標,然後我們有 30 分鐘作為一個 Sprint 來完成一個可交付的產出。時間相當的緊湊,事後想想,如果採用 Scrum 的模型來執行,我們應該每 3 分鐘或 6 分鐘應該進行一次進度的同步工作。然後,在每 3 分鐘到 6 分鐘的時間,為最後的產出做努力。

但是,相場實際的狀況卻是,大家開始討論起該怎麼完成這個產品。整個過程中,我們大約有一半的時間在討論與規劃,就是還沒針對最終產出物捲起袖子開幹。等到,大家討論出一個方針後,我們開始進行製作產品的相關工作。這個 workshop 最有趣的地方,就在於他還必須完成一個 Deployed 的動作。

我們必須讓產品上線,這個 Sprint 才能夠算成功。在製作產品完成後,我們還有五分鐘左右。於是,我們嘗試進行部署。卻發現部署的時間比我們想像的還要久很多。最終,這個 Sprint 我們宣告失敗。

這裡面,其實有很多隱含許多的觀念,底下是自己回顧的心得:

1. 以終為始:我們應該快速地,發布一版到正式環境,以確認團隊了解整個發布程序,並且排除發佈時的風險。對應到實際的案例上,軟體工程師應該都很常遇到,這東西在我們本地端執行都沒問題,但是一移轉到正式環境問題就一大堆。透過這樣的思維邏輯,我們可以更早地面對正式環境的狀況,不會在做了很久之後,才發現有東西需要調整。

2. 用最短的時間產出 End to End 的價值,頻繁地發佈。快速地取得回饋,要比周詳的計畫,但是做了很久專案延宕,無法上線取得價值來說,更有意義。

3. 在之前協同合作時有提到,以拔河為例。當只有一個人的時候,你肯定會用上 100% 的力量。但是,當人一多的時候,大家可能就有所保留。在整個 workshop 中,我們應該沒有發揮整體團隊 100% 的戰力。

4. 快速交付,小步快跑的開發習慣是必須要一段時間練習,讓自己逐漸熟悉這種模式的思維,以任務下來時大家的反應來看。我們都需要一些時間來精熟這樣的模式。

星期五, 11月 17, 2017

Odd-e Certified ScrumMaster 心得分享 2 - 順暢的溝通




順暢的溝通

在二戰之前,法國的陸軍部隊擁有實力堅強的裝甲車設備。但是,在二戰的時候,卻被德國的陸軍打敗。據說,這中間的關鍵就是「溝通」。當時,法國的裝甲車部隊使用旗語在不同的坦克車之間進行溝通,而德國的部隊則是使用「無線電」進行溝通的工作。

在旗語跟無線電之間,我們可以清楚的知道這兩個工具產生的溝通效率不同。使用旗語時,溝通的效果有限,除了距離的限制之外。在作戰期間,坦克車的操作人員也很難時時刻刻探出頭來檢視其他坦克之間的狀況。這使得法國的坦克車部隊,像是一盤散沙,雖然裝備強大但是沒有辦法集中戰力,發揮團隊的力量。

反觀,德國的部隊,因為可以很快的進行有效的溝通工作。當其中一部坦克,打通了某個關卡之後,可以快速地通知其他的夥伴集結,快速地針對現況做出應對與改變,近一步達到戰略上的效果,而獲得最後的勝利。

對比軟體的工作模式,我們可以看到一個團隊雖然共同在打造一個產品,或是執行一個專案。團隊成員之間也有透過會議來進行資訊的同步。但,感覺很多時候,成員跟成員之間還是彼此不知道對方在做什麼,進行怎樣的工作,如何進行。

這使得專案團隊之間,對於產生的問題,或是良好的工法無法有效地快速傳播。所以,我們現在是用「旗語」還是「無線電」?

星期一, 11月 13, 2017

Odd-e Certified ScrumMaster 心得分享 1 - 協同合作



大約在兩年前吧,有一次到趨勢科技參加一個 Scrum 的分享會議,那時候第一次遇到 Daniel 老師。那次會議中分享了如何組成一個 Scrum 團隊,說明了 Cross Function Team 如何組建。

之後,也經常在社群裡,聽聞許多人對於 Daniel 老師的課程讚譽有加,所以當社群內出現了報名資訊後,我就立馬用手機完成了報名程序。接著,過著一段非常忙碌的專案執行生活。一直到上課前一天,都還有著許多工作上煩人的事。

但是,既然都已經報名了這個課程,就必須讓自己放空好好的沈浸在課程之中,以發揮學習最大的效益。

在課程中,我記下了大量的資訊,每一個 Key Word 都有一些啟發,基於養成習慣持續性的交付這項學習心得來看,只好把心得的部分切成許多小的 story 來 release 了!

協同合作

   Scrum 本來就是延伸自橄欖球運動中的爭球,所以一直以來我認為一個良好的 Scrum Team 就是要像一個合作無間的球隊,成員間彼此有默契,能夠互相合作。但是,一個團隊的協同合作就像拔河一樣,當只有一個人的時候,你可能會發揮 100% 的力量。如果,現在我們有一個團隊一起進行,每個人的力量貢獻度就不一定是 100%。

   「協同合作」是我在第一天筆記時,寫下的第一個關鍵字。在第三天,我們在討論什麼是一個好的 Product Backlog 時,卻突然有了體會。在哪份 Product Backlog Item 上,已分配好的工作都有指定一個負責人。

   假設,今天我們在談的是協同合作。一個 Product Backlog Item 為何是指定給特定人士來完成? Product Backlog Item 是一個 User Story,是一個對於客戶來說有價值的 End to End 功能特性的交付。這其中涵蓋許多的細節,包含分析、設計、開發、測試等一切我們必須進行的工作,也是一個交付的目標。

  既然,這是一個目標性的交付,應該是由團隊一起協同合作,完成一個 Product Backlog Item 的交付,否則團隊會在什麼時間點進行合作?

  大家只是各自處理各自的任務,是一個不協同合作的偽團隊罷了!仔細想想,這也是最常看到的分工模式。雖然,大家一起在為一個產品或專案努力,但是彼此之間卻互不相干,不互相幫助。

  一個良好的團隊,應該是共同為一個目標努力。中間有什麼問題需要協助,需要補位,喊一聲就會有人接替。我想,在這樣一個團隊下工作,應該是相當愉快的一件事。所以,也要好好跟團隊同仁分享一下這樣的概念,促進團隊在協同合作上的成長。



星期四, 6月 22, 2017

IBM MobileFirst 7.1 拒絕存取


延續之前 MobileFirst 7.1 的 Server Farm 機制無法正常啟用,經過好一陣子與 IBM Lab 之間的往返,還是沒有一個好的解決方案。


所以,只好考慮直接裝一套新的 Server,並且把專案移轉到新的伺服器上來。
但是,在移轉之後卻出現如上圖所示的錯誤。

因為,通常我們會在 App 啟動時,使用 WL.Client.connect 與 MobileFirst 伺服器連線,以確認 Client 與 Server 之間的版本,並檢查管理者有沒有設定任何通知訊息。

但是,在移轉後,App 端會出現「Access Denied」的錯誤,無法正常啟動 App。

伺服器端,也可以觀察到下列的錯誤訊息:
FWLSE0335E: Authorization failed: 
ClientId f5ac9a8cda443cfca33d1e7f926a71f90f8c67a1 was not found 
on the server.
這個情況,可以透過移除該 App 並且重新安裝,來解除此問題。

所以,我們大概可以推測,MobileFirst 的 Client 端在跟 Server 連結之後,會在手機端留下一些資訊。這些資訊,應該是 MobileFirst 用來確保安全的機制。

1. 可以避免,我們連接到的 Server 與之前的不同
2. 從伺服器端的角度來看,如果先前該手機已經跟伺服器註冊過。但是,現在我們卻無法在伺服器上找到該 ClientId 的話。這個裝置是不是該被視為有問題的裝置。

當然,這種安全機制,有時候還是會造成我們的困擾。

所以,為了避免要求大量使用者重新安裝 App,我們可以採取下列兩種方案,來解決此問題。

1. 在 MobileFirst 7.1 之後,與先前開始有所不同,採用 Session Independent 作為伺服器運作的預設機制。當採用 Session Independent 時,MobileFirst 的相關資訊就會被存於資料庫中。所以,必須調整 MobileFirst 處理 Session 的機制,讓資訊是存於記憶體之中。這樣,就可以解決上述遇到的問題。但是,當採用這樣的機制,勢必會影響到後續 Server 做平行的擴充。所以,除非是以單一機器提供服務,不然不建議採用這個解決方案。

2. 既然,App 移除重裝之後就可以解決此問題。那麼,就是需要在程式中加上一段清除手機上暫存的這些資訊,如此就可以使 App 恢復正常運作。經測試,先前假設沒錯,就是有一段資料被存在手機上。移除之後,就可以正常與伺服器連線。

「參考資料」
1. MobileFirst 7.1 Server Access Denied when using WL.Client.connect API

星期一, 3月 27, 2017

IBM MobileFirst 7.1 WebSphere Liberty Server Farm Unresponsive

前一陣子有客戶反應,他們公司的 MobileFirst Server 無法正常啟動。

於是,開始這段伺服器搶救的過程。

1. 因為 console.log 及 message.log 中都沒有紀錄錯誤訊息,所以為了看更多的資訊,必須打開 trace.log

需要再 server.xml 中加上下列資訊,就可以產生 trace.log 了!
<logging maxfiles="10" maxfilesize="20" 
         tracefilename="trace.log" 
         traceformat="BASIC" 
  tracespecification="com.worklight.*=all:com.worklight.*=all:*=info">
</logging>
中間經歷了很多次重開的過程,Server 就是無法順利啟動。

在沒辦法之下,我只好使用 MobileFirst 的 Configuration-Tool 試著用 update 的方式,中置一下 worklight admin 服務及 runtime environment 的三個 war 檔案。

突然,其中一部 Server 正常啟動了。

心想,應該修好了!

結果在啟動另一個 Server 時,卻卡住了!

這時候剛剛啟動的 Server 也無法正常運作。

觀察一下 tracelog,後來我發現每 30 秒會出現一次下列紀錄

com.worklight.core.clustering.ClusterSynchronizationTask
解到這邊,我一直觀察資料庫內的資料跟伺服器運作的模式。
感覺,就是同步作業失敗,然後一直重做。

上網找了一下資料,看起來跟這個問題比較像的是:
IBM MobileFirst 7.1.0 Liberty Server Farm Unresponsive

但是,內文也是說重建 Server Instance 跟重新設定 Server Farm 就好了!

目前,重建後只能讓單一伺服器恢復運作。
只要想同時啟動 Server Farm 中的兩個伺服器,就會陷入同步失敗的問題。

現在還在等 IBM 原廠回覆此問題的正確解法。

星期二, 8月 09, 2016

Kendo Grid 教學 4 - 解決 REST Service 回應 HTTP 403

在先前「RestTemplate 無法呼叫 Rest Service」的文章中有提到,有些後台被 Spring Security 保護著,並啟用 Cross-site request forgery (CSRF) 的保護機制,並免他人因為知道服務的端點,就可以直接呼叫相關的服務。

Kendo UI 可以透過 Datasource 中 transport 的屬性設定,可以完成資料的讀取及寫入工作。針對新增、修改、刪除及查詢的部分,分別提供 create、update、destory 及 read 的 function 來進行相關作業的處理。
    transport:{
        create:{...},
        update:{...},
        destroy{...},
        read{...}
    }
開發人員可透過上述設定,完成 kendo grid 上 CRUD 的相關動作。

但是,當我們碰上後端具有 CSRF 保護的服務時,可能會出現 「HTTP 403 : Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'」的錯誤訊息。

這代表,我們正常地呼叫後端的服務。以整合 Spring Security 來說,當我們完成登入後,可以從 Request Header 中觀察到,HTTP Request 都會帶著兩個 Cookies 的資訊,分別是 JSESSIONID 及 XSRF-TOKEN 資訊。

然後,我們再看一下錯誤的訊息「HTTP 403 : Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'」。看起來,後端要的服務需要我們的 Header 送一個 X-CSRF-TOKEN 的資訊過去。上網找一下參考資料「Invalid CSRF Token 'null' 解決方案」看起來也是這樣說明沒錯。而且,X-CSRF-TOKEN 的內容跟 XSRF-TOKEN 一樣 (一樣的東西,底層竟然沒有自己處理掉 .... 看來還要找時間看看到底為什麼有這樣的限制)。 

所以,接著要思考的是如何在 Kendo Grid 呼叫後端服務時,將  X-CSRF-TOKEN 動態的塞入。後來,我在 「Transport and basic authentication」找到了解答。我們可以在 create、update、destroy 跟 read 等方法上加上 「beforeSend」的方法來加入 X-CSRF-TOKEN。

beforeSend: function(req){
    req.setRequestHeader('X-XSRF-TOKEN', $cookies.get('XSRF-TOKEN'));
}
如此一來,就可以正常使用後端服務了!

[參考資料]
1. 跨網站請求偽造
2. Invalid CSRF Token 'null' 解決方案
3. Transport and basic authentication

星期一, 8月 08, 2016

RestTemplate 無法呼叫 Rest Service

最近有人問我一個問題,現象是他的應用程式呼叫被 Spring Security 保護的服務時,如果未將 csrf disable,系統就無法正常運作。

Spring Security 啟用 CSRF 後可保護 Server Side 的 Resource,避免跨網域攻擊 (從別的機器發出 Request 以取得後端的資訊)。所以,當 Spring Security 啟用 CSRF 後,我們會在前端的頁面加上

   <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>

以便,證明我們是從同一個網域發送的請求。

然而,這個問題卻不是上述原因造成!第一時間的猜想錯誤,所以我就開始檢視程式碼內容,來看看到底那邊出了問題。

後來,發現在後端的程式中有一段使用 RestTemplate 去呼叫 REST 服務。基本上,如果在內部應該可以直接呼叫相關的物件,而不需要透過 RestTemplate 來進行呼叫 (多繞了一圈)。不過,依照範例來看是個教學程式,所以就先不討論合理性的問題。

RestTemplate 其實是一個增強化的 HTTP Client ,所以在使用 RestTemplate 時我們可以想像自己開了一個新的瀏覽器,然後存取該服務。此時,RestTemplate 中根本就沒有儲存相關的 Session。因為他的 Request 中沒有帶任何經過驗證的資訊。所以,會被 Spring Security 視為不合法的存取。

我們必須在 RestTemplate 中加入一些資訊,才可讓這個呼叫合法。相關資訊,可參考下列參考資訊的網址。

HttpHeaders headers = new HttpHeaders();
headers.add("cookie", req.getHeader("cookie"));
HttpEntity requestEntity = new HttpEntity(null, headers);
ResponseEntity rssResponse =
restTemplate.exchange( your_service_url,
HttpMethod.GET,
requestEntity, List.class);
1. 建立 HttpHeader 物件,並將 request header 中的 cookie 值取出,設定到自己建立的 HttpHeader 中。(因為 Session 就存在這裡)

2. 建立 HttpEntity 物件,並利用先前建立的 HttpHeader 進行初始化。

3. 使用 restTemplate 呼叫後端服務,取得 ResponseEntity 以進行後續邏輯運算


[參考資料]

星期三, 8月 03, 2016

Kendo Grid 教學 3 - 建立新增功能

在 「Kendo Grid 教學 2 - Inline Edit」的文章中提到怎麼樣進行 inline edit 的工作。但是,以先前提供的範例來看,並未交代如何進行新增的作業。

但是,如果有依據參考資料進入 「Kendo Grid Grid Inline Edit Demo」檢視範官方的範例程式的話,應該已經發現如何把「Add New Record」的按鈕加上去。

$scope.mainGridOptions = {
    dataSource: $scope.datasource,
    pageable: true,
         height: 300,
toolbar: ["create"],
    columns: [
     { field: "id",  title: "商品編號", width: "120px"},
     { field: "name", title: "商品名稱", width: "120px" },
      { field: "price", title: "商品價格", width: "120px"},
{ command: ["edit", "destroy"], title: "&nbsp;", width: "250px" }
          ],
editable: 'inline'
};
};
在原本 mainGridOptions 中,加入 toolbar 的元素,並指定要使用 create 功能,就可以像官方的範例,有一個 「Add New Record」的按鈕。

當這個按鈕按下去之後,以 inline 編輯模式來看,Kendo Grid 的第一行會進入編輯模式,讓我們輸入資料後進行新增作業。

[參考資料]
1. Kendo Grid Grid Inline Edit Demo

星期三, 7月 27, 2016

Kendo Grid 教學 2 - Inline Edit

在 「Kendo Grid 教學 1 - 建立列表」的文章中,有兩個主要的變數要設定,以便讓 Kendo Grid 可以運作起來,並透過 Rest Service 拿到列表資訊。分別是 datasource 與 mainGridOptions。

Datasource

其中,datasource 可以看作是 kendo grid 的資料來源。在先前的文章中,設定了 transport 與 schema  兩個主要屬性。

transport


透過 transport 的屬性設定,可以完成資料的讀取及寫入工作。針對新增、修改、刪除及查詢的部分,分別提供 create、update、destory 及 read 的 function 來進行相關作業的處理。
    transport:{
        create:{...},
        update:{...},
        destroy{...},
        read{...}
    }
開發人員可透過上述設定,完成 kendo grid 上 CRUD 的相關動作。

schema

Schema 在 Datasource 中扮演兩個重要的角色:

  1. 透過 schema.model.fields 定義 kendo grid 的資料模型,設定排序 (sorting)、篩選 (filtering),並確保使用對應的編輯元件,例如: 數字輸入框對應到數字型別的資料。
  2. 透過 schema.model.id 定義 kendo grid 中的 id 欄位,以確保新增、修改、刪除等工作可以正確執行。

schema: {
      model: {
           id: "id", 
           fields: {
                 id: { editable: false, nullable: true, defaultValue: null},
                 name: {validation: { required: true }},
                 price: { type: 'number', defaultValue: 0, validation: { required: true, min: 0}}
           }
       }
}



parameterMap

在 Kendo Grid 與後端服務整合的部分,透過設定可以採用 json, jsonp, odata 等不同資料模式。所以,在請求資料 (request) 真的往後送之前,我們需要透過 parameterMap function 幫我們處理資料的轉置問題。

下列為,parameterMap 中的範例程式。因為 read 方法不需要傳參數即可拿到資料,所以在範例程式中,我們把 read 方法過濾掉。然而,在 create, update 及 destory 的部分,我們將前端 Form 內的第一個元素取出 (因為 options.models 預設是 array),並將其當作參數往後面的服務拋送。

parameterMap: function(options, operation) {
if (operation !== "read" && options.models) {
        return JSON.stringify(options.models[0]);
     }
 }


mainGridOptions


在前一篇文章中,我們有看到下列 mainGridOptions 之設定。設定的內容可以進一步分成幾個區塊。


  1. 設定 datasource,作為 kendo grid 的資料來源
  2. 利用 pageable 設定是否分頁
  3. 透過 height 設定 kendo grid 的高度
  4. 透過 columns 設定 kendo grid 的表頭應該呈現什麼
    4.1. filed 的設定會與 datasource 底下 schema 內的 fields 做呼應,相同名稱的會對在一起,是一種透過設定抓相對應資料的概念。
  5. columns 中還有一個設定為 command,在每一列上會顯示編輯 (edit) 與刪除 (destory) 的按鈕
  6. editable 設定為 inline 代表該 grid 會使用 inline 的方式進行編輯作業
      其中,標紅色字樣的部分是本次要做 inline edit 新加的部分


$scope.mainGridOptions = {
    dataSource: $scope.datasource,
    pageable: true,
         height: 300,
    columns: [
     { field: "id",  title: "商品編號", width: "120px"},
     { field: "name", title: "商品名稱", width: "120px" },
      { field: "price", title: "商品價格", width: "120px"},
{ command: ["edit", "destroy"], title: "&nbsp;", width: "250px" }
          ],
editable: 'inline'
};
};

建立對應新增、修改、刪除、查詢的方法

在本文前面有提到 datasource 中的 transport 就是讓我們進行 create、update、destory 及 read 的 function 撰寫。

在本文中,以 update 為例:

1. url : 記錄遠端服務的端點
2. type:  使用 HTTP  通訊協定的方法 (例如:GET, PUT, POST, DELETE 等)
3. contentType 傳輸內容的類型
4. complete function: 服務呼叫成功後,要做的相關動作可以寫在此處
5. error function: 服務呼叫失敗後,要做的相關動作可以寫在此處

update: {
     url: "your service endpoint",
     type: "PUT",
     dataType: "json",
     contentType: 'application/json',
     complete: function (data) {
// 呼叫服務成功後,要做什麼事
     },
     error: function (xhr, error) {
         // 呼叫服務失敗後,要做什麼事
     }
}

其他,關於 destory 及 create 也是採用相同的方式進行撰寫。雖然,在這裡並沒有說明如何建立一筆新的資料。但,後面還會有其他文章提到。

備註:
我們做 Rest Service 的時候,可能經常將 create、update 及 delete 的 method 預設為不回傳值。以 Java 來說,就是宣告回傳的是 void。

但是,這樣可能會導致 kendo grid 不 work。所以,我們必須回傳一個 JSON 字串回來。針對,create 及 update 的方法,需要回傳新增或是更新的那個物件回來。避免 kendo grid 呈現一個空白列在那邊。

有關 inline edit 的實際 demo,可以進一步參考官網上 Inline Edit 的範例。

「參考資料」
1. Kendo Grid CRUD Data Operation
2. Kendo Grid Grid Inline Edit Demo

Kendo Grid 教學 1 - 建立列表

近年來,前端 javascript 的技術突飛猛進,有許多的 framework 出現,學都學不完。而在,公司的專案需求上,我們需要開始研究 Kendo UI 這套框架。

Grid View 是我們建置 Web 應用程式中相當常用的 UI 元件。記得十多年前,同時接觸 .NET 與 Java 時,總覺得為什麼 .NET 上做一個 Grid View 相當容易,而在 Java 上卻需要自己寫那麼多程式。一個 Page 一個 Page  一直寫著重覆類似的程式碼。

雖然知道,這裡應該要被元件化,但始終沒有下手去做這類整理的事。那時候,還是以 Server Page 為主的時代。AJAX 的興起是在那之後兩三年的事情。

而到了現在,檯面上已經有非常多這種前端的元件,而且透過 javascript 技術的發展。現在,前端的頁面已經鮮少使用 Server Page 相關的 Tag 。而改由 HTML5 + javascript + css 來進行所有的事情。至於後端採用什麼語言 (C#, Java or PHP) 似乎已經沒那麼重要,也徹底實現 Web 端的 MVC 概念。

底下,我們就建立一系列的文章,來探討使用 Kendo UI 的心路歷程:

1. 下載 kendo ui 的相關套件 Kendo UI Download Free Trial
 
解壓縮後,將套件內的 js 與  styles 資料夾放到專案目錄中。以我自己的範例來看,這兩個資料夾放在 [your project]/webapp/resources/lib/ui/ 底下。

2. 下載 kendo.all.min.js

我是認為 kendo.all.min.js 應該涵蓋在第一步驟中所下載的內容裡。但是,不知道為什麼沒有。可能這樣可以收一點顧問費,畢竟它是需要付費的!所以,只好從官網的範例偷偷把 js 檔載回來。一樣放在 [your project]/webapp/resources/lib/ui/ 底下。

此使,該目錄下有 js 及 styles 兩個資料夾再加上 kendo.all.min.js 這個檔案。

3. 建立後端 RESTFUL Services,讓 Service 回傳下列這串 JSON 訊息回來

[
  {"id":4,"name":"Starbucks","price":300},
  {"id":5,"name":"BrownCafe","price":200},
  {"id":6,"name":"CityCafe","price":100}
]
4. 撰寫前端頁面

4.1. CSS 與 JS 引用之宣告

<link rel="stylesheet" href="./resources/scripts/lib/ui/styles/kendo.common.min.css" />
<link rel="stylesheet" href="./resources/scripts/lib/ui/styles/kendo.default.min.css" />
<link rel="stylesheet" href="./resources/scripts/lib/ui/styles/kendo.default.mobile.min.css" />
<script src="./resources/scripts/lib/ui/js/jquery.min.js"></script>
<script src="./resources/scripts/lib/ui/js/angular.min.js"></script>
<script src="./resources/scripts/lib/ui/kendo.all.min.js"></script>
4.2. 在 HTML 頁面上,宣告要使用 Kendo Grid (以 AngularJS 為範例,官網上還有許多 JQuery 的範例)

<div id="example" >
    <div ng-controller="MyCtrl">
        <kendo-grid options="mainGridOptions">
        </kendo-grid>
    </div>
</div>
4.3. AngularJS

4.3.1. kendo UI 元件在 AngularJS 中被實作成 directives 所以當我們要使用 kendo ui 時需要注入 kendo.directives
var app = angular.module('myApp', ['kendo.directives']);
4.3.2. Controller

app.controller('MyCtrl', function($scope){
$scope.datasource = {
transport: {
read: {
url: [your service address]
dataType: "json"
}
},
schema: {  
model: {
                 fields: {
                    id: { editable: false},
                    name: {validation: { required: true }},
                        price: { type: 'number', defaultValue: 0, validation: { required: true, min: 0}}
                    }
                }
            }
};
$scope.mainGridOptions = {
    dataSource: $scope.datasource,
    pageable: true,
         height: 300,
    columns: [
     { field: "id",  title: "商品編號", width: "120px"},
     { field: "name", title: "商品名稱", width: "120px" },
      { field: "price", title: "商品價格", width: "120px"},
          ]
};
};
依據此方式,即可完成下列表格之設計。雖然,做了很多事才弄出這張表。但是,使用這個元件可以讓後續新增、修改跟刪除的 UI 操作快很多,只需要再加上一些設定。




[參考資料]
1. Kendo UI - Grid Example

星期一, 7月 25, 2016

IBM MobileFirst 7.1 DirectUpdate 失效


最近,有客戶反應他們的 MobileFirst Server 升級到 7.1 後,Direct Update 僅能更新一次,之後就無法再進行更新。

因為客戶說,他們當天要準備上線作業,這個功能必須能正常運作。所以,我跟同事就開始研究問題可能發生的原因。

根據客戶描述,一開始的時候是部署 wlapp 到 MobileFirst Console 時會出現警告訊息如下:


FWLSE3210W: Environment: android of application [YOUR Application] 
version 1.1 has been deployed with a different version of the native 
MobileFirst SDK. 

Direct updates will no longer be available for existing clients with 
other versions of the MobileFirst SDK. 

To Continue to use direct updates, increment the app version, publish it 
to the public app store, deploy to the server, and (optionally) block/notify 
older versions of the app to enforce customers to upgrade to the new version 
from the app store.

針對上述部分,需要修改 wlapp 的版本。因為 version 1.1 的時候是使用 MobileFirst 先前的版本進行打包。依據 IBM 對於 Direct Update 的定義來看,如果有 Native SDK 更新的話,是必須整個 App 重新下載安裝,而非僅更新 Web Content 就可以。

而升級的時候,IBM MobileFirst 底層的 SDK 有可能被更換掉,所以會出現上述訊息。故,我們將 version 1.1 換成 1.2。如此,在部署 wlapp 時,就不會有 FWLSE3210W 的警告訊息。

但是,上述問題解決後。客戶驗證 Direct Update 的系統發現還是只能更新一次。所以,問題實際上還沒有被解決。

後來,我們又發現 worklight.properties 檔案中,有一個參數是 wl.realm.expiration.directUpdate 的值預設為 3600 (一小時內,Direct Update 不會再生效)。在舊版的值似乎是 -1。但是,目前設定 -1  MobileFirst Server 又無法正常啟動。所以,只好設定個 60 秒 (反正改程式應該都會超過一分鐘吧!)。

修改後,重新更新 MobileFirst Server 的 Runtime WAR 檔之後,Direct Update 的更新頻率就換成1分鐘後可重覆更新的模式。

[參考資料]
1. The direct update doesn't work in MobileFirst Studio v7.1


星期四, 8月 13, 2015

Certificate Scrum Developer 認證課程心得




最近剛上完 Certificate Scrum Developer 課程,授課老師是 Jacky Shen。在這門課程當中討論「持續整合」,「TDD」,「重構」,「Simple Design」,「Git version control」,「Pair Programming」等相關議題。

在最近一年的時間裡,我陸續取得 PMI-ACP,CSPO 及CSM等證照。有了這些知識,卻感覺還少那麼一點東西。Scrum 團隊有 Product Owner,Scrum  Master 及 Development Team 這三個角色。其中,Team 的人數最多,卻很少有人坐下來好好地把什麼是一個好的 Development Team,以及我們該如何成為這樣的團隊。

所以,有 Product Owner 的認證,有 Scrum Master 的認證,當然我們也需要知道如何培養自己或是團隊成為一個敏捷開發團隊成員之一。所以,基於一個這樣的念頭,讓我在颱風隔天連續上了兩天 12 小時的馬拉松課程。


從整個課程的內容來看,初步可以將課程內容分成兩個主要觀念。

          (1) 專注品質

1.1. 在課程中有提到許多好的程式概念,例如:程式碼要讓其他人一目了然,快速地了解。程式碼要可被信賴。程式碼必須是可維護的。

1.2. Test Driven Development: 確保每一段程式碼都有其對應可執行的測試案例。

1.3. 頻繁且持續地測試,保持程式碼永遠是可動的,並且合於需求。

1.4. 透過重構,不斷地改善程式碼的品質,降低程式的壞味道。

          (2) 減少浪費

2.1. 不做過度的設計,減少浪費。

2.2. 花時間進行重構,可以降低日後一次性大規模的調整。(這讓我想起「不要惹公司的程式設計師啊」。)

2.3. 建立自動化的測試案例,可以降低人為測試不斷重工的浪費。


但是,我認為上述的內容還不是最重要的。在 Scrum Alliance 的網站上,說明怎樣是一個成功的 CSD?

A successful Scrum Developer is committed to continuous improvement.

課程最重要的內容是

讀書、練習、分享

努力不懈地提升自己,透過練習不斷地提升自己實務的能力,並且將這些知識分享出去,發揮影響力,讓團隊可以更精進。

最後,感謝長宏的團隊促成以及一起上完這兩天馬拉松式課程的同學們,讓這次Certificate Scrum Developer 課程能在百般的艱難下開課成功。感謝 Jacky  老師充實的課程使大家獲益良多。

星期日, 5月 03, 2015

Deploy IBM Worklight Server to WebSphere Liberty Profile Manually


最近,有一個客戶要將 IBM Mobile First 7 安裝在 AIX 6.1 上。但是,在裝好後,我卻發現 MobileFirst Platform 的目錄中沒有 Worklight Configuration Tool。

心裡面的OS是,這不是IBM的產品嗎?為什麼沒有自家 OS 的工具。

所以,只好開始研究看看,怎麼手動將 Worklight Server 手動佈到伺服器上。

首先,第一步就是檢視 MobileFirst 的安裝目錄,看看裡面有什麼設定檔,反正根據過去經驗應該可以找到一些東西。

終於,在 WorklightServer 的資料夾底下,找到 configuration-samples 的資料夾。在這裡面發現了許多的 xml 檔案 (例如:configure-liberty-db2.xml)。從這些檔案的命名規則,大概可以推敲出可能的解決方案。

於是,我將該檔案打開來進行編輯。依據 xml 檔案內容的提示,置換相關的資料進去。

隨後,執行下列幾個指令:

ant -f configure-liberty-db2.xml admdatabases
ant -f configure-liberty-db2.xml databases

ant -f configure-liberty-db2.xml adminstall

ant -f configure-liberty-db2.xml install

記得每個指令執行後都必須要看到 BUILD SUCCESSFUL 關鍵字,才可以執行下一個指令。


[參考資料]
1. IBM Mobile First 7 Knowledge Center

星期一, 3月 30, 2015

Windows 磁碟壓縮後 Microsoft SQL Server 無法正常使用

使用 Apple Mac Book Pro 最大的問題應該就是硬碟空間太小。

前幾天,我電腦中 windows 的 VM 空間滿了。讓我無法執行寫程式與測試的工作 (因為只要想寫檔案,系統就會出現,磁碟空間不足的錯誤訊息)。

所以,在這種清況下,為了清出空間來使用,只好使用 Windows 的磁碟壓縮功能。

服用後,多出了 20%左右的空間,使得手邊的工作得以繼續。

就在這兩天,我準備打開 Microsoft SQL Server 進行一些相關技術驗證時,就出現資料庫檔案是壓縮檔,無法正常使用的錯誤。

於是,我開始在網路上找尋 solution,花了十幾分鐘,也沒看到一個好的建議方案。


只好自己想辦法處理。如果跟據先前的分析來看,我應該要設法解除磁碟壓縮的狀態。

但是,如果解決磁碟壓縮,就會面臨空間不足的另外一個問題。所以,只好探索是否能部份解除。

後來,我在相關的資料夾的進階設定選單中發現了設定選項。解除該資料夾底下的磁碟壓縮狀態。

設定方法如下:
1. 選定該資料夾,按右鍵選擇「內容」,並且點選「進階」按鈕
2. 系統跳出右邊視窗,取消勾選「壓縮內容,節省磁碟空間(C)」

弄完後,Microsoft SQL Server 就恢復正常了!

星期二, 1月 20, 2015

修改 WebSphere Application Server 上的 JESSIONID cookie name

       Java Servlet API 2.5 之前規定,session identification coolie 必須叫做 JESSIONID。但是,這個規定在 Servlet API 3.0 後已經解除,而 WebSphere Application Server 第八版之後就已經支援 Java Servlet API 3.0 的規格,所以我們可以修改 WebSphere Application Server 上的 JESSIONID cookie name。

        基於,以上的原因。最近突然有人說有改這個東西。當然,先前完全沒改過這個項目!所以,到 IBM 的 Knowledge Center 翻出了下列修改方式:


1. 開啓 WebSphere Application Server 管理主控台
2. 選擇 Servers > Application Servers > Server_Name > Web Container Settings > Session management > Enable Cookies
3. 修改 Session Cookie 的值,預設為“JSESSIONID”
4. 點選確認,然後儲存相關修改設定
5. 重新啟動 WebSphere Application Server
6. 重新啟動 plugin 檔案

待確認問題:
1. 假設在 Cluster 的環境上,我們只修改某一台 Server 的 JESSION Cookie Name 會發生什麼事?

2. 如果 WebSphere Application Server 上裝著以前的舊程式 (Java Servlet API 2.5 以前),會不會被影響?

3. 修改後的 plugin-cfg.xml 會有什麼變化?

4. 這個跟 IBM HTTP Server 以及 WebSphere Application Server Plugin 的版本有沒有關係 (例如:IBM HTTP Server v7.0 是否支援)?


未完,待續 .....


參考資料:
1. 修改 HTTP Cookie Name