Hello Java DB and JDK6

0

源起

JDK 6 內建一個小型內嵌資料庫,改自 Apache Derby 專案,有機會變成 JavaSE 內建的資料庫,值得看看。

參考連結

  1. 之前的 Dreby bundle 包裝紀錄。
  1. 必看的 Java DB 官方網頁。

classpath 仍需要設定

一開始聽到的會以為現在只要下載 JDK 就可以直接寫個 Class.forName( “org.apache.derby.jdbc.EmbeddedDriver” ) 來用, 不過目前還不行,由於還不是 JavaSE 內建 API,屬於延伸的東西, 還是需要去設定 classpath 才能運作,只是換個名稱並包在 JDK 下載之中而已。

export CLASSPATH=.:${DERBY_INSTALL}/lib/derby.jar

這樣做的好處是只要指定 JDK6 的目錄為 JAVA_HOME,就代表可以找到 相對位置的 JAVA_HOME/db/lib/derby.jar。

export CLASSPATH=.:${JAVA_HOME}/db/lib/derby.jar

很類似之前 Tomcat 需要 JDK 編譯的時代,那時需要指定 JAVA_HOME/lib/tools.jar 才能運作,後來 Tomcat 改用 eclipse jdt 編譯器,就不再需要 JDK 部署,只要 JRE 就能跑。

觀察

  1. 功能和 Apache Derby 無差異,只是差在名稱變成 Java DB,並可以由 sun 提供 支援服務,目前手冊等資料還是連到 Apache Derby 取得。
  2. 就使用者簡易性來說,Java DB 需要綁在 java -classpath 的做法比較麻煩, OSGi 動態載入 Apache Derby bundle 會比較方便。

Hello ant1.7 and junit4

0

源起

現在慢慢習慣使用 Junit4 寫測試,發現目前 eclipse 3.2 支援的 ant 1.6.5 的 junit task 不支援 junit4,所以想試一下新的 ant1.7。

junit 4

除了 @Test 之外,目前測試 spring 的 bean 往往都是一次取得 application context 來測,這時候 @BeforeClass 也是很好用。

ant 1.7

目前是 RC 版,先下載 apache-ant-1.7.0RC1-bin.zip,解開為目錄。 然後開 eclipse 的 ant 設定,將其中的 Ant Home 換成 1.7 的目錄即可。

<target name="test" depends="compile">
  <junit printsummary="yes">
    <classpath refid="supportlib.classpath"/>
    <formatter type="xml" />
    <batchtest fork="yes" todir="${reports.tests}">
      <fileset dir="${src.test}">
        <include name="**/*Test*.java" />
      </fileset>
    </batchtest>
  </junit>
</target>

<target name="report" depends="test">
  <junitreport todir="${reports}"> 
    <fileset dir="${reports.tests}"> 
      <include name="TEST-*.xml"/> 
    </fileset> 
    <report 
        format="frames" todir="${reports}/html"/> 
  </junitreport> 
</target>

觀察

  1. 雖然 junit 3 的支援比較完整,不過新東西還是要試一下。

Hello JAXB2 and JavaSE6

0

源起

幾個專案用過 XMLBeans,還不錯用,之前評估過 JAXB 1.0 版本,有兩個問題, 一是 XML Schema 支援有點問題,一是 JAXB 當時有商業授權等議題。

這些專案是採 XML Schema 為主的做法,也就是需要先由客戶端決定商業領域的語法, 交付寫好的 schema,那時 JAXB 1 沒辦法很方便的foo.xsd 轉 foo.java, 而 foo.xsd 一直改到後期會越來越複雜,一堆的 complex type,所以那時找到能 符合專案 schema 與授權的方案是 BEA 釋出的 Apache XMLBeans。

不過時過境遷,現在 JAXB 2 授權也改了,支援 XML schema 應該也 比較好,同時 JavaSE6 已經內建支援,於是來玩看看。

http://download.java.net/jdk6/docs/technotes/guides/xml/jaxb/index.html

scheam-first or code-first

如果先寫 schema 的話,需要使用 xjc,就 eclipse 來說,使用 ant 比較方便。 不過 com.sun.tools.xjc.XJCTask 並不存在 JRE 中,需要下載 jaxb-xjc.jar 來用。

https://jaxb.dev.java.net/nonav/2.0.2/docs/xjcTask.html

https://jaxb.dev.java.net/

用 xjc 產生 java 碼後,就可以開始用。

ProjectType pj = new ProjectType();
...[SKIP]
ObjectFactory objFactory = new ObjectFactory();
JAXBElement<ProjectType> je = objFactory.createProject(pj);

JAXBContext jc = JAXBContext.newInstance(ProjectType.class);
Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

簡單 marshaller.marshal(jaxbElement, System.out) 的結果。

<ns2:project xmlns:ns2="http://config.service.haha/ns/project">
    <profile>
        <name>FOO PROJECT</name>
    </profile>
</ns2:project>

更換 ns2

指定預設或是更動命名空間的 prefix 並不在 JAXB2 的規格 (JSR-222 spec) 中, 所以 JAVA6 平台無法提供這類的 marshaller 機制,要用 JAXB2 RI 才可以, 因為有的 schema 的 prefix 名稱是定死的,不支援這個會比較麻煩。

//  RI 才有支援,需要 jaxb-impl.jar,JAVA6  不包含
marshller.setProperty("com.sun.xml.bind.namespacePrefixMapper",
  new NamespacePrefixMapper() {
    @Override
    public String getPreferredPrefix(String nsuri,
               String suggestion, boolean requirePrefix) {
        // 無法調成 default 只能改掉。用 "" 無效 ?
        if ("http://config.service.haha/ns/project".equals(nsuri))
            return "pj";
        return suggestion;
      }
    });

結果輸出

<pj:project xmlns:pj="http://config.service.haha/ns/project">
    <profile>
        <name>FOO PROJECT</name>
    </profile>
</pj:project>

取部份 XML 輸出

之前用 XMLBeans 都用複製 copy 模式建立另一個文件來修改取出需要的部份, JAXB 似乎沒有這類方式,需要建立兩個物件複製。

haha.remix.jaxb

基本上就是轉包 jaxb-api.jar, jaxb-impl.jar, jsr173_1.0_api.jar 供 OSGi 平台使用, JAVA6 雖然有支援 JAXB2,但是需要 com.sun.xml.bind.namespacePrefixMapper 的情況下, 還是要使用附加的 jaxb-impl.jar。

另外使用 haha.remix.jaxb 讓 JAVA5 也一樣可以用。

JAVA6

根據 Java 6 Leads Out of the Box Server Performance 的說法,這個快上很多的出場預設性能蠻吸引人的。

觀察

  1. 因為 JAXB 已經是個標準,關於 JAXB 的用法還要再深入觀察。
  2. 個人目前用起來 XMLBeans 比較直覺,也有可能是用習慣的關係。
  3. 簡單的綁定, JAVA 6 是個不錯的現成平台,如果要更細部的支援,無可避免還是要加 jar 到平台上,這時 JAXB2 RI 或是 XMLBeans 就看哪個用的順手,功能也都可以提供為主。

Hello TargetSourceLifecycleListener

0

源起

啟動 jetty bundle 後,如果想要修改 jetty 由 spring 控制的 init() 啟動 port 為 8080, 這時在 osgi console 下 update 指令,其他 bundle 註冊的 webapp 是否會改由新的 8080 進入,需要哪些設定,想要觀察一下。

jetty 發佈服務設定

服務端的設定如下 :

<bean id="httpServiceImpl" 
  class="haha.service.jetty.HttpServiceImpl" 
  init-method="init" 
  destroy-method="destroy" 
  p:port="80" 
  p:debugEnable="true"/>
<osgi:service ref="httpServiceImpl" 
  interface="haha.service.publishing.WebPublishingService"/>

使用發布服務並將資料交給發布者

之前的做法如下 :

<osgi:reference id="webPublishingService" 
  interface="haha.service.publishing.WebPublishingService" />
<bean id="publisher" class="haha.service.jetty.PublisherImpl" 
  init-method="init" destroy-method="destroy" p:webappDir="webapp" 
  p:contextPath="/foo" autowire="byType" />

結果 update jetty 後,該發佈服務並沒有跟著改為新的 port, 因為之前的做法綁定在 init(),並無法反映服務的中斷與重新啟用, ,所以需要類似 OSGi DS 規範的服務綁定功能。

TargetSourceLifecycleListener

之前的做法是利用 setter 將服務注入,並在 init() 發布,現在改用 spring-osgi 提供的 TargetSourceLifecycleListener 介面加以實做,在 bind/unbind 中寫下使用 的服務內容,用 osgi:listener 來注入這個服務。

<bean id="publisher" class="haha.service.jetty.PublisherImpl" 
  p:webappDir="webapp" p:contextPath="/foo" />
<osgi:reference id="webPublishingService" 
  interface="haha.service.publishing.WebPublishingService">
  <osgi:listener ref="publisher" />
</osgi:reference>

因為由 bind 注入因素,可以省掉 autowire=”byType” 的注入方式。

觀察

  1. osgi:listener 可以設定 bind/unbind 的 method,幫助現有 API 轉用,不一定要用 TargetSourceLifecycleListener。
  2. 這裡用內含新 p:port 的 bundle 來並下載更新來達到目的,如果要由客戶端 改自己改要如何做 ?

Hello Big Tiger with Terracotta

0

源起

看到這篇 Terracotta 介紹 後,想要試試,當我們同在一起,是否其快樂無比,做法是將兩隻老虎 (Java5) 變成一隻大老虎看看。

Terracotta 官方網站 以及這篇練習的 Hello 範例 參考。

DSO Server Node

先從 DSO 版本下手,下載 windows/linux 版約50MB 來用,這個安裝有自帶一個 JRE,所以不裝 JRE 也可以用,windows 裝完大約在 C:\Program Files\Terracotta\terracotta-2.2 可以找到。

因為要不同機器執行,和範例的本機執行有差別,要改一下東西才能跑。

先複製 \dso\config-sample\tc-config-dso.xml 為 tc-config-hello.xml。 改 /tc:tc-config/servers/server[@name and @host] 為 windows 機器的 ip。

start-tc-server.bat" -f ..\config-sample\tc-config-hello.xml

這個 tc-server 會啟動一個 HTTP 服務可以看輸出的訊息,例如啟動在 9510。

  1. http://192.168.111.194:9510/ 會對應到 C:\Program Files\Terracotta\terracotta-2.2 目錄。
  2. http://192.168.111.194:9510/config 輸出整個設定 XML,這個檔是關鍵。

JMX 的部份可以直接開 AdminConsole.exe 來看。

Tiger 1 DSO Client Node

這次要測的 HelloWorld 類似一張黑板,每個人(JVM)上去寫現在日期(執行一次)後, 大家都可以看到內容。

利用之前的 tiger1 當 Client Node 的環境,參閱 Hello Two Tigers

客戶端更簡單,不需要設定檔,直接在網路上抓 server node 的執行就可以。

/dso/bin/dso-java.sh -Dtc.config=http://192.168.1.9:9510/config tutorial.HelloWorld

tiger2 如法炮製,只要裝好 terracotta 後,將 java 換成 dso-java 並註明一下 server node 設定檔就可以多一台,接下部署要幾台有幾台。

保存

萬一 server node 關掉,狀態需要保存,就需要加個設定,將資料放在檔案中。

<persistence>
    <mode>permanent-store</mode>
 </persistence>

這樣可以不需要資料庫也可以保存狀態。只是兩種存放可能都是必須的,舉例來說,一張下午飲料訂購單上,傳來傳去,刪刪減減中,突然停電,這時狀態保留在 server node,開機後繼續傳閱填單子,最後負責人要保留這張單子並副本給飲料店。

這時候應該還是需要某種 ORM 將單子存到 DB 來保存,方便以後查詢。

飲料單可能是半天,員工旅行或是意見單前前後後也許要幾星期,不能保持狀態在 server node 實在太危險,這類延續數天數星期的事件,中間是否需要保留到 DB ,多久保留一次都是需要觀察的問題。

至於是否可以就讓這張單子一直躺在 server node ? 可能還需要時間檢視,完全不用 DB 來保存是否會有其他問題。

關於 一直躺著的問題 有人提到,雖說還不到某種 OODB 的實現,目前要做到的狀況跟現實差不多,現實需要一個 放在角落的櫃子來放這些單子,如果這個櫃子不是用 ORM 連結展示的 DB,就必須是某種櫃子物件,這樣才有連結 reference 可以找到其中放置的單子來取資料。

換句話說,保存搜尋的這個過程中,你要查閱某張單子,都需要先找到放的容器來找,暫時性的也許是承辦人的抽屜 (DSO) ,永久性也許是地下室架上的櫃子 (DB TABLE)。

不用 Terracotta

下面列舉想到的一些做法,可能需要考慮用資料庫或是某種保存程式來存放狀態,並提供同步所有點的即時物件狀態查詢。

  1. object-JDBC-DB-JDBC-object
  2. object-ORM-DB-ORM-object
  3. object-OXM-SOAP-WS-SOAP-OXM-object

觀察

  1. 在 windows 平台,一開起 start-tc-server.bat 會立刻吃掉近 250MB 記憶體,改一下 Xms64m Xmx128m 才能在小機器玩一下。
  2. 因為具有所謂的穿透性,說明程式不用改,可以直接在數十台直接部署,新增物件時,到 server node 改一下 tc-config.xml 就可以。
  3. server node 很像物件即時狀態交換中心,效率與同步衝突等等議題還有待練習觀察。
  4. JVM network 是個星狀網路,連結是採用 TCP/IP ,需要一直保持連線,如果斷掉連線 再回來,會回復到目前最新狀態。

Older posts: 1 2 3 4 5 ... 18