Hello Mylar

0

源起

Mylar 是一個 Eclipse 上面的附加工具,這個工具主要是轉變工作的方式,把原先的專案檔案 (project/file) 為主的開發方式,轉為工作流程 (task) 為主的方式。

參考

  1. Mylar 官方
  2. Mylar Getting Started
  3. Introduction to Mylar
  4. Mylar 試用後強力推薦
  5. About Mylar 1.0

舉例

舉一個 Spring-OSGi 的 bundle 來說,變動一個服務內容需要下面幾個檔案,這類變動不是 refactoring 可以幫你代勞的那種,通常是比較巨大的變動與新增。

File-Focused 檔案觀點如下 :

  1. [Service Interface Bundle] /src/haha/service/FooService.java/haha()
  2. [Service Interface Bundle] /META-INF/MANIFEST.MF/Import-Package: xx
  3. [Service Implement Bundle] /src/haha/service/FooServiceImpl.java/haha()
  4. [Service Implement Bundle] /MEAT-INF/MANIFEST.MF/Export-Package: xx
  5. [Service Implement Bundle] /MEAT-INF/spring/service-beans.xml/..
  6. [Service Implement Bundle] /test/haha/service/FooServiceImplTest.java/..
  7. [Service Implement Bundle] /test/haha/service/FooServiceImplTest.xml/..
  8. [Service Client Bundle] /src/haha/client/FooServiceClient.java/..
  9. [Service Client Bundle] /MEAT-INF/MANIFEST.MF/..
  10. [Service Client Bundle] /MEAT-INF/spring/client-beans.xml/..
  11. [Service Client Bundle] /test/haha/client/FooServiceClientImplTest.java/..
  12. [Service Client Bundle] /test/haha/client/FooServiceClientImplTest.xml/..

總計有 12 個檔案,每個檔案可能有數個地方需要更改,影響所及可能達到數十個地方。過幾個月後,即使是原負責寫的人來改,也要許多時間來重複達到之前做過的路徑,這中間 unit test 可以協助確保沒有改錯或是動到其他地方,但是對提高修改速度還是需要某些工具。

自己寫的都會如此,更何況是原先都尚未接觸的人接手修改。

Mylar 讓你跳脫出來,不用 12 個檔案中間有數十個地方要改的眼光去看這件事,這會讓全盤考慮受到阻礙,而是用 1 個工作流程 (變動服務內容) 來看,同時這個工作流程可以交換保留,方便後續維護工作。

Task-Focused 工作流程觀點如下,只剩下一個 :

  1. Modify Service Task

Mylar 簡易流程

  1. 新增 task
  2. Active Task
  3. 開啟編輯文件。
  4. 預設值自動將開編輯器的文件部份加入 context。
  5. 關閉編輯器會將文件整個文件退出這個 task。
  6. 很多文件開的時候,一定要關掉一些,記得關掉編輯文件前, 要先按 pause capturing context 再關 (1.0 裝好沒有按鈕,下拉不好找), 直接關整個檔案會被取消掉。
  7. Deactive Task

消失的 pause 按鈕

用過一陣子之後,可以體會為何 Mylar 1.0 正式版將那個暫停功能藏起來,其實是很人性的做法,因為你往往會做著做著忘了已經暫停,這時候 Mylar 幾乎沒有用。

不需要暫停的原因是根本不需要關 editor,這是 File-Focused 的習慣, 因為開開關關成為一種編輯習慣,突然 Mylar 讓你都不用關會很不習慣,往往一不注意就關掉 editor。

所以應用 Mylar 應該開了就不要關掉 editor,除非真的沒興趣才關, 不要有興趣的檔案,為了省開幾個 editor,在哪裡一直按 pause 。

那要是幾百個檔案有興趣,整個編輯區不就滿滿都是一堆 editor ? 其實不用去關或管這些 editor,讓 Mylar 去做就可以,專注於你的 task 才是 Mylar 應用的重點,其他的交給 Mylar 去做就好。

觀察

  1. 習慣不要關掉 editor,因為已經篩過,要關掉要注意 task 的 active 問題。
  2. 轉換工作方式需要動到許多舊的東西,也許從新專案開始比較好。
  3. 是否需要裝 issue tracking system,如果是小專案應該就不用, 如果是大專案,還是要裝一下比較好,看起來 Trac 不錯,只是裝了就要維護,這也必須考量。

A Chain of Spring-OSGi Services

0

源起

使用 TargetSourceLifecycleListener 可以讓客端在服務發生變動時加以因應,這是一對一的場景, 如果是一連串的相依服務串在一起的場景,要如何因應某個 bundle 的變化。

參考

  1. Hello TargetSourceLifeCycleListener

場景

下面為練習場景,假設 http 啟動的 port 由 conf bundle 控制。

  1. Conf Bundle(ConfService)
  2. Jetty Bundle(ConfListener/JettyService)
  3. WebApp Bundle(JettyListener)

修改 Conf Bundle 後先停止。

Stop ConfBundle

  1. [Jetty Bundle] ConfListener.unbind
  2. [Conf Bundle] ConfService.destroy

然後啟動,這時候會在 bind 中如果發現 port 不同會重新啟動

Start ConfBundle

  1. [Conf Bundle] ConfService.init
  2. [Jetty Bundle] ConfListener.bind (restart http service)

這時候 WebAppBundle 一無所知,因為 JettyBundle 沒有被 stop/start, 而是 ConfBundle stop/start。

這時要這些 WebAppBundle 重新註冊,需要 JettyBundle 的 stop/start, 來觸動 JettyListener。

Stop JettyBundle

  1. [WebApp Bundle] JettyListener.unbind
  2. [Jetty Bundle] JettyService.destroy (stop http service)
  3. [Jetty Bundle] ConfListener.unbind

Start JettyBundle

  1. [Jetty Bundle] JettyService.init (start http service)
  2. [Jetty Bundle] ConfListener.bind (restart service)
  3. [WebApp Bundle] JettyListener.bind

這時候因為整個 JettyBundle 的重新啟用,導致屬於這個 bundle 的 ApplicationContext 再來一次,這讓 ConfListener.bind 又被呼叫一次。

bind 被呼叫兩次的原因。

  1. service 端重新啟動觸發 bind method。
  2. bundle 本端重新啟動,為了觸發下游 bundle 的 bind method。

setter method to inject ConfService

為了避免呼叫兩次,一開始將 bind 的 restart http service 去掉,只讓 init 啟動,不過發現 bind 的方式必須在 bean 實體化之後,也就是說在 init 之後才會呼叫 bind,如此一來要設定讓 http service 使用修改後的 port 會有 問題。

另外可以在 init 之前完成的是 setter 注入 ConfService 的方式,這樣一來, ConfBundle 的重新啟動,並不會對 JettyService 有任何作用,改 port 的行為 必須直到 JettyBundle 重新啟動才會生效。

觀察

  1. ConfBundle 一改,下面的相關 Bundle 也需要跟著重新啟動,來觸發下游的 bind method, 以修改 port 為例,需要 ConfBundle,JettyBundl 兩個 bundle 先後依順序重新啟動。
  2. ConfBundle 修改導致所有相關 Bundle 都需各別再啟動的方式也許有其他更好做法,有待繼續觀察。
  3. bind/unbind 需要由可由輸出服務的 bundle start/stop 觸發,也會由自己的 bundle start/stop 觸發。
  4. stop bundle 會先呼叫 bean unbind method 後呼叫 bean destroy method。
  5. start bundle 會先呼叫 bena init method 後呼叫 bean bind method。

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 就看哪個用的順手,功能也都可以提供為主。

Older posts: 1 2 3 4 ... 8