2018年9月12日星期三

JNDI + Derby + TomEE Plus 教學

JNDI 用來做甚麼?


JNDI 全名是 Java Naming and Directory Interface,重點在於【Naming】及【Directory】這兩個字,簡單來說,就是查冊服務,用【名字】來查找需要的【目錄 / 服務】。

舉例,香港公共圖書館借書時,有沒有留意書背?那組數字加英文就是索書號 ( Naming ),是個獨一無異的名字,只要用這個名字搜尋公共圖書館目錄 ( Directory ) 就一定找得到想要的書。

與 Database 用 Primary key 搜尋有甚麼分別?


用途不同,Database 用於處理資料,Database 需要頻繁讀寫,而 JNDI 主要透過設定 J2EE container 更新資源,查找  ( lookup ) 目錄 / 服務 / object 等,只需設定一次就好,不會經常改動設定檔吧?

JNDI 目錄 / 服務有甚麼?


放甚麼都可以,不像 Database 那樣,有 data type 及資料長度限制。JNDI 常見用法有以下幾項︰

  • Datasource
  • LDAP ( Lightweight Directory Access Protocol )
  • WSDL ( Web Services Description Language )
  • entry ejb

本文只示範 datasource 設定及使用,日後有機會再補上其餘三項。


———————————簡易的分隔線————————————

快速查閱︰


廢話不多說,想根基札實就順著看,想速食跳著看也不反對,沒有基礎跳步學,總有天會遇上瓶頸︰




———————————簡易的分隔線————————————

JNDI 結構︰


jndiarch.jpg

https://docs.oracle.com/javase/jndi/tutorial/getStarted/overview/index.html

這是官網 JNDI 介紹圖,還是很複雜?太抽象?以下有自畫解說圖。

TomEE_config.png

用 TomEE 這個 J2EE container 做例子,簡單來說,分成三部份︰

Client︰


用 JNDI API 寫程式,透過 API 連結 TomEE Server。

參考資料︰
https://mobiarch.wordpress.com/2012/12/07/configuring-a-mysql-data-source-in-tomee/

Server︰


設定 conf/tomee.xml 及補充其他資源。

例如在 tomee.xml 設定 datasource 後,要在 <TommEE-HOME>\lib 放入 JDBC Driver ( .jar 之類 )。因應使用,會有各式各樣設定及補充,用到時再說,現在先記住。

其他 Server 及服務︰


連接其他 Server 協作,透過 TommEE Server 取得及設定其他 Server 服務。

透過更改 Tomee.xml 等方式設定參數,例如 connection pool、LDAP 等等,好處是 Client 不需要更改程式碼,交給 TomEE 做設定。

設定好 datasource 放入 JNDI,Client 可以透過 JNDI 取得 object 使用,本文會做範例。

好處︰


Database administrator、server administrator、 web application developer 各自負責自己專業,只需要把接合點處理好,提供所需資料,其他設定及調整可各自處理,分工合作。

舉例,Database administrator 只需要管好 database,不影響資料結構下,做甚麼都行 (eg. Database normalization),提供資料庫 IP、ID 及 password 給 server administrator 做設定 (eg. tomee.xml)。

server administrator 可以設定 Connection Pool 等,提升資源效率,web application developer 通知
server administrator 選用 embbedderby 或是 clientderby,提供 JDBC driver 放進 JNDI。

web application developer 專注程式碼,提取資料,其他瑣碎事都不用管 (eg. server config、 database config、networking 等等)。

壞處︰


以上好處,聽上去很美好,但架構變得複雜,需要一個能掌握全局的人分配工作 (eg. software architecture),協調各專業人員合作。

好處及壞處都是假的!全部!都是!假的!Full Stack Developer 才是真的!別發夢了,一個人做三四五人職務才是現實!看實際需求,沒必要把問題複雜化,想清楚,要不要用到隔好幾重山的方法,要把複雜度 ( complexity ) 考慮進去。

———————————簡易的分隔線————————————

以 JSP 用 JNDI 連結 Database 重點如下︰


放 JdbcDriver 進 <TomEE_Home>\lib


從 Derby 的 lib 抄一份 derby.jar 到 TomEE 的 lib。

設定 TomEE.xml


  <Resource id="FirstDB_datasource" type="DataSource">
JdbcDriver org.apache.derby.jdbc.EmbeddedDriver
JdbcUrl jdbc:derby:A:\\javatoybox\\Database\\FirstDB
UserName Stanley
Password javatoybox
  </Resource>

參考資料︰
https://db.apache.org/derby/docs/10.14/devguide/cdevdvlp40653.html
http://tomee.apache.org/common-datasource-configurations.html

設定 web.xml


<resource-ref>
<description>Example for TomEE + JNDI + Derby</description>
<res-ref-name>jdbc/FirstDB_datasource</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>

參考資料︰
https://tomcat.apache.org/tomcat-7.0-doc/jndi-datasource-examples-howto.html#Oracle_8i,_9i_&_10g

編寫 jsp 程式碼


Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/FirstDB_datasource");
Connection con = ds.getConnection();

參考資料︰
https://stackoverflow.com/questions/38078459/how-to-obtain-datasource-from-resources-in-tomee-7
https://examples.javacodegeeks.com/enterprise-java/tomcat/tomcat-datasource-jndi-example/

———————————簡易的分隔線————————————

以 Eclipse 實作︰


前置準備︰


這裡綜合了好幾個技術,需要前置準備,例如安裝 J2EE container ( TomEE Plus ) 及有資料的 Database ( Derby )

Eclipse 上使用 Apache TomEE
https://javatoybox.blogspot.com/2018/07/eclipse-apache-tomee.html

Eclipse 上使用 Java DB ( Apache Derby ) (PART 1 / 3 )
https://javatoybox.blogspot.com/2018/05/eclipse-java-db-apache-derby-part-1-3.html

註︰Derby 做完 PART 1 就好,目的是建好資料庫。前置準備很麻煩吧? 因此有 Docker 出現,有興趣可以 Google 一下。順帶一提,除了做技術可行性評估及十萬火急任務外,個人不建議用 Docker,要學習就該由安裝及設定開始,這對 debug 及 problem-solving 有幫助。

Source and dockerfile
https://github.com/IntegrityKnight/Docker-Tomee-Derby

Use docker image
https://javatoybox.blogspot.com/2018/09/docker.html#use-docker

Build docker image
https://javatoybox.blogspot.com/2018/10/docker-eclipse-docker-image.html

流程︰


  1. 放 JDBC Driver 進 TomEE plus
  2. 設定 TomEE.xml
  3. 建立 JSP 項目
  4. 設定 web.xml
  5. 編寫 JSP 程式碼
  6. 部署 ( Deploy ) JSP
  7. 起動 TomEE 伺服器
  8. 測試結果

———————————簡易的分隔線————————————

操作截圖︰



EmbedderDriver 對應 derby.jar,把這個抄一份放入 TomEE。

ClientDriver 對應 derbyclient.jar,用這個做練習,把程式碼改成這個,最好要把 derby 教學 1、2、3 part 看完才動手試。

JNDI_Derby_0.png

設定 JNDI 有甚麼可用資源,如上述重點,尋找資源時,id 大小寫要一致才能找到。

JNDI_Derby_1.png

建立【Dynamic Web Project】。給個 Project name 及 設定 Targt runtime 到【tomee-plus-7.0.4】( 視符改了甚麼名  )。

Next 到某一步,一定要選 Generate web.xml 這個!下個步驟會用到!

JNDI_Derby_2.png

修改 <ProjectName>/WebContent/WEB-INF/web.xml,設定 JSP 能拿到 JNDI 甚麼資源。

JNDI_Derby_3.png

在【WebContent】右鍵,新增 JSP,要選 (html) 版本。XML 版本 JSP,在編譯時會有不符合 XML 定義而出現 Error。

JSP XML Support
https://docs.oracle.com/cd/A97688_16/generic.903/a97679/jspxml.htm

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>DataSource JNDI</title>
</head>
<body>
<%@ page import="java.sql.*, javax.sql.*, javax.naming.*" %>
<%
Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/FirstDB_datasource");
Connection con = ds.getConnection();
String sql = "SELECT id, actor, product FROM acg_character.profile";

Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
ResultSet rs = stmt.executeQuery(sql);
ResultSetMetaData rsmd = rs.getMetaData();

out.print("<table border=\"1\">");
out.print("<tr>");
int cols = rsmd.getColumnCount();
for (int i = 1; i <= cols; i++) {
// print Column Names

out.print("<th>" + rsmd.getColumnLabel(i) + "</th>");

}
out.print("</tr>");

while (rs.next()) {
int id = rs.getInt(1);
String actor = rs.getString(2);
String product = rs.getString(3);
out.print("<tr>");
out.print("<td>"+ id + "</td>");
out.print("<td>"+ actor + "</td>");
out.print("<td>"+ product + "</td>");
out.print("</tr>");
}
out.print("</table>");
rs.close();
stmt.close();
%>
</body>
</html>


貼上 datasource.jsp 程式碼。

JNDI_Derby_4.png

只有開【Dynamic Web Project】才可以 Export 成 WAR file。

JNDI_Derby_5.png

Deploy 到 TomEE 伺服器,最好把【Overwrite】打勾,這樣做就不會每次問,要不要覆蓋檔案。

JNDI_Derby_6.png

啟動 TomEE 後,WAR file 會自動爆開。每次修改程式後,Export WAR 到這個路經,會自動重新 deploy。


Deploying in TomEE
http://tomee.apache.org/deploying-in-tomee.html

JNDI_Derby_7.png
開內建 web browser 看結果,格式是 http://<網址>/<WAR 檔案名>/< WAR 裡面的 JSP>
( eg. http://localhost:8080/TomEE-JNDI-Derby-Example/datasource.jsp )

———————————簡易的分隔線————————————

總結︰


JNDI 說起來好像很複雜,但做過練習,了解結構及設定後,其實很簡單。

以上 JSP 範例不是好的編程方法,只為降低複雜度而用 Scriptlet。正常來說,以 Servlet 做後台處理,JSTL 做展示,進階一點用 Apache Struts 這類 framework。

有時間的話,去了解 Model View Controller (MVC),會有更多體驗。


沒有留言:

發佈留言

設有留言驗證及審查,檢閱後,才會顯示留言。
本人惰性很高,留言或許會石沉大海。