雖說是下篇,說是上篇也行。對像艾力克林這樣的角色來說,本來要教他東西,他就說你做個Sample最快,變成在幫他做他本來該做的事,而且還符合艾力克林的另一個要求,若沒法子幫他在Eclipse建置好環境,就不會開發,不會自己去找怎麼在Eclipse上work的方式或是在沒有Eclipse輔助下的work。廢話完畢,在Eclipse上Run Equinox的問題其實還不少,首先是設定OSGi Framework的執行環境,Eclipse預設是用Equinox,而Eclipse本身的運作就是Equinox為平台。 在安裝新的Eclipse 3.5 SR1版後,最好一開始就設好Menu上的Run/[Run Configuration]的OSGi Framework選項。而我遇到的反模式是,import Equinox官方網站的QuickStart兩個飯粒後,對其中一個專案按右鍵選Run/OSGi Framework,如此一來Eclipse會先預先幫設好一個OSGi Framework,名為New_Configuration,而且是什麼Jar檔都匯入。

上圖是點選[Run/Run Configuration]後Popup的介面。第一、先在左側清單OSGi Framework按右鍵點[Add],會出現右側的設定頁面。而預設值是全選,是故第二、按[Deselect All],取消所有的OSGi Jar,只選所需要的Jar。而若不是跑Web,只要挑到org.eclipse.osgi_
version_
vDate的Jar,就可以Run Equinox平台了。若想跑Jetty Web Server,請見上篇。
import sample project很簡單,但要開啟一個全新的OSGi Project怎麼處理?點選File/New,挑[Plug-in Project]後按[Next]出現以下畫面:

直接輸入Project Name就可按[Next],紅框內Eclipse version和an OSGi framework差別在提供的Templates多寡而已,Eclipse version當然支援較多Eclipse自身提供的Jar。

Activator類別會把Project Name作為預設Package,可手動修改Package Name和Class Name,按[Next]。

到這裡Eclipse提供眾多Template可以code generate,而an OSGi framework的Templates就較少些。都不選Template按[Finish]也會直接幫你code generate一個Activator.java和一個目錄META-INF以其底下的MANIFEST.MF(還有一個build.properties檔,但只對Eclipse有用),然後可以選擇切換成到PDE(Plug-in Develop Env)環境,出現MANIFEST.MF的GUI介面讓你編輯,如下:
第二個頁籤[Dependencies]可以透過[Add]按鈕import其它OSGi Jar提供的Export功能,在我裝了Maven的Eclipse Plugin後,連Maven也提供export Jar可以import,它是看你手上資源有多少就顯示多少。 寫完一個OSGi Jar後,可以按Project Name上按右鍵點選Run/OSGi Framework,就可以在Console頁籤看到osgi>提示了。而OSGi Framework也可以設定多個,比如只有Run OSGi核心,或是具有支援http功能的,這樣會比較好些。通常在osgi>提示下輸入ss,應該大部份都是ACTIVE狀態,若是INSTALLED狀態,表示有安裝沒運作,可以下達:start ID,看它會出現什麼Exception。在上篇測試sample.http.registry時,知道是需要
org.eclipse.equinox.http.registry這個套件,但根據Exception指示,該套件卻還需要import
org.eclipse.equinox.common和
org.eclipse.equinox.registry才行。和書中寫的不同,估計Equinox到Eclipse 3.5.1 SR1版,又做出一個registry抽象層導致。
Jemmy 發表在 痞客邦 留言(0) 人氣(221)
連兩天打麻將,晚上就研究Equinox在Eclipse的官網上的QuickStart兩個Sample飯粒。昨天小輸,研究也遇瓶頸,今天小贏,終於也了解這兩個Sample在搞什麼把戲。 在http://www.eclipse.org/equinox/server/http_in_container.php,可以下載sample.http和sample.http.registry兩顆飯粒。這兩個差別是前者透過程式碼去定義Servlet或html去對映URL,後者則是透過設定檔去對映,而後者要import的Jar比前者多些。先講前者: 在Equinox上Run Jetty要import的Jar的檔清單 | id State Bundle 0 ACTIVE org.eclipse.osgi_3.5.1.R35x_v20090827 1 ACTIVE org.eclipse.osgi.util_3.2.0.v20090520-1800 2 ACTIVE org.apache.commons.logging_1.0.4.v200904062259 3 ACTIVE javax.servlet.jsp_2.0.0.v200806031607 4 ACTIVE org.mortbay.jetty.util_6.1.15.v200905182336 5 ACTIVE javax.servlet_2.5.0.v200806031605 6 ACTIVE org.eclipse.equinox.http.jetty_2.0.0.v20090520-1800 7 ACTIVE org.mortbay.jetty.server_6.1.15.v200905151201 8 ACTIVE org.eclipse.osgi.services_3.2.0.v20090520-1800 9 ACTIVE org.eclipse.equinox.http.servlet_1.0.200.v20090520-1800 |
在MENIFEST.MF的設定:Import以下的設定,均是用程式碼對映Servlet所需。 | Import-Package: javax.servlet, javax.servlet.http, org.osgi.framework;version="1.3.0", org.osgi.service.http;version="1.2.0", org.osgi.util.tracker;version="1.3.1" |
程式碼(sample.http.Activator.java) | import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.osgi.service.http.HttpService; import org.osgi.util.tracker.ServiceTracker; public class Activator implements BundleActivator { private ServiceTracker httpServiceTracker; public void start(BundleContext context) throws Exception { httpServiceTracker = new HttpServiceTracker(context); // 呼叫內部類別 Step 0 httpServiceTracker.open(); } public void stop(BundleContext context) throws Exception { httpServiceTracker.close(); httpServiceTracker = null; } private class HttpServiceTracker extends ServiceTracker { // 寫個內部類別繼承ServiceTracer Step 1 public HttpServiceTracker(BundleContext context) { super(context, HttpService.class.getName(), null); } public Object addingService(ServiceReference reference) { // 對映Servlet與URL主程式 HttpService httpService = (HttpService) context.getService(reference); // Step 2 try { httpService.registerResources("/helloworld.html", "/helloworld.html", null); // Step3 httpService.registerServlet("/helloworld", new HelloWorldServlet(), null, null); // Step3 } catch (Exception e) { e.printStackTrace(); } return httpService; } public void removedService(ServiceReference reference, Object service) { // 無作用時記得取消對映。 HttpService httpService = (HttpService) service; httpService.unregister("/helloworld.html"); httpService.unregister("/helloworld"); super.removedService(reference, service); } } } |
上例中,HelloWorldServlet是一個標準的Servlet Class,沒有任何和OSGi有關的置入性code。因果關係可以上面標出的Step看出,而Step 3的HttpService的兩個method:registerResources與registerServlet,第一個參數是URL,第二個參數是對映的實體,new HelloServlet()沒問題,而/helloworld.html是指向與META-INF目錄同層。
像HttpService一個個設定URL與實體資源的對映很麻煩,而sample.http.registry飯粒就提供像web.xml設定的功能(如果能做到把WAR當作一個OSGi Jar更好,但Equinox平台目前還看不出,而別的平台如Spring的dm Server似乎可以)。 在Equinox上Run Jetty的清單以外,還得加以下的Jar: | 3 ACTIVE org.eclipse.equinox.http.registry_1.0.200.v20090520-1800 14 ACTIVE org.eclipse.equinox.common_3.5.1.R35x_v20090807-1100 15 ACTIVE org.eclipse.equinox.registry_3.4.100.v20090520-1800 |
在MENIFEST.MF的設定:只需import javax.servlet和javax.servlet.http,另外需要加上: | Require-Bundle: org.eclipse.equinox.http.registry |
在plugin.xml設定,plugin.xml需與META-INF目錄同層。 | <?xml version="1.0" encoding="UTF-8"?> <?eclipse version="3.0"?> <plugin> <extension-point id="servlets" name="HttpService servlets" schema="schema/servlets.exsd"/> <extension-point id="resources" name="HttpService resources" schema="schema/resources.exsd"/> <extension-point id="httpcontexts" name="HttpService httpcontexts" schema="schema/httpcontexts.exsd"/> <extension id="helloServlet" point="org.eclipse.equinox.http.registry.servlets"> <servlet alias="/ext1/helloworld" class="sample.http.registry.HelloWorldServlet"> <init-param name="servlet-name" value="Test Servlet"> </init-param> <init-param name="testParam" value="test param value"> </init-param> </servlet> </extension> <extension id="helloResource" point="org.eclipse.equinox.http.registry.resources"> <resource alias="/ext1/helloworld.html" base-name="/helloworld.html" /> </extension> </plugin> |
一個extension子標籤是一個URL(alias屬性)對映一個Servlet或Resource(由point屬性定義)。理解web.xml的設定,上述的定義也大概略知一二。 而在Suvery過程,遇到最多的麻煩其實是Eclipse在Run OSGi Framework的設定,能事先找出什麼原因,就不用再繼續踹Error了。這部份見下篇。 Jemmy 發表在 痞客邦 留言(0) 人氣(211)
大年初三,到台北晃了一下,許久未逛重慶南路的書店,差點錯過一本簡體中文書:OSGi原理與最佳實踐。而我的Eclipse 3.5因安裝了Pax,org.eclipse.org核心套件被遮蔽,只好再下載新的Eclipse 3.5的SR1版,其OSGi核心也升級了。這次內容是用OSGi啟動Http Server,而Eclipse預設用的是Jetty,書中示例用Eclipse 3.4,而我根據其package內選了如下:
id State Bundle
0 ACTIVE org.eclipse.osgi_3.5.1.R35x_v20090827 (OSGi核心)
1 ACTIVE org.eclipse.osgi.util_3.2.0.v20090520-1800 (我加的)
2 ACTIVE org.apache.commons.logging_1.0.4.v200904062259 (必須)
3 ACTIVE javax.servlet.jsp_2.0.0.v200806031607 (我加的)
4 ACTIVE org.mortbay.jetty.util_6.1.15.v200905182336 (我加的)
5 ACTIVE javax.servlet_2.5.0.v200806031605 (必須)
6 ACTIVE org.eclipse.equinox.http.jetty_2.0.0.v20090520-1800 (必須,Equinox對Jetty)
7 ACTIVE org.mortbay.jetty.server_6.1.15.v200905151201 (必須,Jetty Server)
8 ACTIVE org.eclipse.osgi.services_3.2.0.v20090520-1800 (必須)
9 ACTIVE org.eclipse.equinox.http.servlet_1.0.200.v20090520-1800 (必須) 果然輸入http://localhost後,出現Jetty版的HTTP ERROR 404,表示Jetty Server有在運作。而在[Run Configuration]裡編輯OSGi Framework裡的Arguments頁籤裡的VM arguments,在原有參數後添加以下內容,就可以變成Listen 8080 port了: -Dorg.osgi.service.http.port=8080 最大的抱怨是,當上次結束[Run Configuration]是停留在OSGi Framework設定下,下次啟動[Run Configuration]時,在Load OSGi bundles等得超久,一兩分鐘要吧!Jemmy 發表在 痞客邦 留言(2) 人氣(91)
Modular Java提供的MavenSpider飯粒還真不好煮。OSGi架構概念很簡單,也因為簡單,Pax就有很多複雜的Script協助建構複雜的bundle,否則自己兜一個中大型的Bundles可能更糟。 每個Pax的script都會直接影響到執行目錄下的pom.xml,比如pax-import-bundle -g groupID -a artifactID -v version,其實作用就是把import進來的bundle jar加到pom.xml的dependencies;而pax-create-bundle,除了在project目錄下建立bundle子目錄,還會在project目錄下的pom.xml增加module,其值就是bundle的目錄名。 另外意想不到一點,PowerShell居然有不少屬於Unix Like的指令,ls和dir效果完全一模一樣,還有cp、ps等,但後面帶的參數就有很多情況不太適用,如ps -ef、ls -la等等。後來查了PowerShell in action,其實是別名設一樣而已。
Jemmy 發表在 痞客邦 留言(0) 人氣(13)
在PowerShell上執行Pax Construct還不賴,它提供的介面比cmd好看多了。在PowerShell上執行OSGi興許有不一樣的火花。Pax Construct提供兩個script:pax-embed-jar和pax-wrap-jar把Jar包成bundle。 Bundle在OSGi裡最簡單的定義是一個普通的jar加個額外的資訊檔,即META-INF下的MANIFEST.MF。而要介紹的這兩個script,甚至可以幫忙從Jar檔找出相依(dependencies)的Jar,generate MANIFEST.MF的資訊。 pax-embed-jar和pax-wrap-jar從其名稱判斷兩者差別:Embed Jar是把相依的Jar全涵蓋進來包成一個bundle,這些dependencies只屬這個bundle,所以它需在bundle目錄下執行,即由pax-create-bundle所建的目錄,相當WAR檔結構;而Wrap Jar則是在pax-create-project所建的目錄下執行,一個project可有數個bundle,依賴共同的dependencies,是故當dependencies有所變動,相依的Bundle都得重新編譯,感覺像沒有用到OSGi的特點,但在開發家族系列的Bundle就有需要。 Pax Construct能自動生成MANIFEST.MF的資訊,在執行pax-create-project或pax-create-bundle後。switch到bundle目錄下,執行: pax-embed-jar -g org.compass-project -a compass -v 2.2.0 就會把來自org.compass-project的compass的jar檔內嵌到bundle目錄/target/pax-eclipse下,同時也改變了bundle目錄下的osgi.bnd內容。而compass又會牽拖一大堆目前還不需要用到的jar檔,如Spring、TopeLink、Hibernate等,怎麼辦?在osgi.bnd裡再加一行如下面的粗體字: Embed-Dependency: compass;groupId=org.compass-project;inline=false
Import-Package: *;resolution:=optional 這樣在進行mvn clean install包出的bundle jar不會因為找不到dependencies而無法編譯成功。 再switch到上一層的project目錄,執行: pax-wrap-jar -g org.compass-project -a compass -v 2.2.0 和上個語法完全一樣,但output目錄不同,dependencies jar檔compass和bundle jar均產出到project目錄下的runner/bundles下,而compass在wrap也有和embed一樣的問題,因為執行上述script後,會在project目錄多出一個org.compass-project.compass的子目錄,按指定group ID.artifact ID產出,其目錄下也有個osgi.bnd,也可以在再加一行一樣的內容如下: Embed-Dependency: *;scope=compile|runtime;type=!pom;inline=true
Import-Package: *;resolution:=optional 從這裡看出,wrap jar因為dependencies要被數個bundle共用,是故獨立出一個子目錄方便進行生成MANIFEST.MF。而embed jar的dependencies則跟著bundle目錄走。
Jemmy 發表在 痞客邦 留言(0) 人氣(32)
Survey IDE的操作,如Eclipse,提供一大堆選擇與按鈕功能讓你無所適從,不知漏了什麼動作會有什麼後果。其實IDE的任務在於協助不在於主導,是故它都有提供最簡易的情況,不用想太多去做一些設定,就直接Run看看實驗一下。 Pax Runner除了有Maven plugin以外,也有Eclipse plugin,通常只需用Maven plugin就好,不過也看看Eclipse plugin能提供強大的功能。 Pax Runner原本並沒有自己的Eclipse plugin,而是有個Pax Cursor專案專責於Eclipse驅動Pax Runner,目前是0.9.0版,但因附屬性太強,於2009/5/28併到Pax Runner專案,目前支援到Pax Runner v1.3版。其plugin的url是
http://www.ops4j.org/pax/eclipse/update/。 Pax Cursor在Eclipse提供的介面頗令人驚艷,在[Run Configurations]找到OSGi Framework,去new一個新的Configuration,Pax Cursor多增加一個名為Pax Runner的頁籤,長相如下:

可選的功能不少,先從最簡單的入手,用[Add Bundle…]新增一個bundle jar,然後再切到Bundles頁籤,可支援的OSGi Container也變豐富了,長相如下:

未安裝前,Framework的下拉選單只有Equinox,安裝後,不但有各家的OSGi container列表,而且還列出每家container的版本清單,不同版本支援OSGi程度也就不一樣。而做了實驗結果,除了沒有版本編號的Equinox之外,凡有via Pax Runner的framework選項,才會理會Pax Runner所做的設定。而一開始測試時,所有bundles都不要選就可以work,然後因為Pax Runner有加了一個bundle,會被載入。此外要等別注意,所有的bundles不是都能選,像org.eclipse.osgi_3.5.0.20090520是OSGi的核心,會與Pax Runner提供的OSGi核心衝突,無法載入,但還是能work。 藉由Pax Cursor才了解到,除了Equinox、Felix和Knopflerfish外,還有個後起之秀Concierge。Pax Umbrella專案,隸屬OPS4J的組織,和Apache和codehause有些類似,樂見他們的貢獻。
Jemmy 發表在 痞客邦 留言(0) 人氣(123)
Pax Umbrella Project是為發展OSGi Tool的專案(Pax umbrella譯作大同傘)。提供不少獨立的工具,大概以Pax Construtct和Pax Runner為主。Pax Construct負責建構OSGi相關專案如Bundle、Module、Service等;而Pax Runner則是可以建立OSGi container,可以選擇Felix(預設)、Equinox或是其它的OSGi container等,Pax Runner還真是跟流行,作用和SLF4J之於Logger、JPA之於ORM差不多。 自
http://wiki.ops4j.org/display/paxconstruct/Download下載最新的Pax Construct(目前最新版是1.4),壓縮後,增加Pax Construct的Home/bin的目錄到Path。以下是部份script用法: 【pax-create-project】 建立一個Pax專案,不帶參數時會依次向你要求Maven所需的group ID、artifact ID、version,或是直接帶參數如下: pax-create-project -g groupId -a artifactId [-v version] [-o] [—mvnOpts ...] 假設artifactId是my,執行完後會產出my這個子目錄,在Eclipse去import Maven Project選擇my目錄,然後只勾選最頂層的pom.xml(子pom.xml則不要勾選),如此就能在Eclipse建立一個名為my的project。 【pax-version】 這是執行Pax Runner的script,可以在command mode下執行,預設Run Felix。也可以改變為Equinox,在my目錄下的pom.xml做以下的修改: 1.在build/plugins標籤增加如下,因Maven預設JRE是1.4,是故要改成1.5。 <plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin> 2.修改maven-pax-plugin設定使用Equinox,有點長: <plugin>
<groupId>org.ops4j</groupId>
<artifactId>maven-pax-plugin</artifactId>
<version>1.4</version>
<configuration>
<!--
| some example Pax-Runner settings
<provision>
<param>platform=felix</param>
</provision>
-->
<provision>
<param>--platform=equinox</param>
<param>--profiles=minimal</param>
</provision>
</configuration>
<executions>
<execution> <!-- 原本被註解 -->
<id>ide-support</id>
<goals>
<goal>eclipse</goal>
</goals>
</execution>
</executions>
</plugin> 這樣執行pax-version就會改為Equinox。而不管是Felix或Equinox,也可以使用Maven指令在Eclipse啟動OSGi container。其指令是
mvn pax:version。
Jemmy 發表在 痞客邦 留言(0) 人氣(75)
在Eclipse 3.4以上,[Run Configurations]裡有個OSGi Framework的設定,現在終於了解怎麼用,不過會建議開個command mode去用會比較好,因為osgi>提示是在Console View顯示,而像comipler、版本控制等,很多功能會使用Console view。所以開個command mode執行Equinox會單純很多。 在[Run Configurations]裡有個[OSGi Framework]按右鍵選新增,會等很久後才出現如下的畫面:

在Bundles裡的Target Platform列了很多bundle,其實都可以不用選,只選一樣org.eclipse.osgi後按[Run]就可以Eclipse下啟動OSGi container了。若真的執意想在Eclipse上run,千萬不要直接按[Run],按[Apply]後在把右邊的游標移離剛設定好的command,不然每次一開[Run Configurations]都等很久。 Eclipse、Spring、Struts2和JPA其實都已支援OSGi,但有多少人會關注呢?OSGi輕薄短小,連手機都可以嵌入,cloud computing for Java solution的unisersal middleware的選擇,應該也是OSGi。
Jemmy 發表在 痞客邦 留言(0) 人氣(162)
斥資千圓大洋,購進一本薄薄的原文書:Modular Java。它是講OSGi(我真有錢)。 今天上午Demo了Maven,也讓與會者感嘆,若Vibo案早點引進不就好了。除了富邦案和現在這個案子,有誰敢給這個時間去踹一個不見得會成功的技術,就算是有七成把握,PM們也不願冒三成的風險,除了這兩個案子的當時的老板外。我當然有看錯的時候,Ruby on Rails沒有預期的紅,但它的約定優於配置的概念卻影響深遠。 今年不斷嘗試framework所需的新技術,除了Maven以外,其實到處都有OSGi的蹤影。Struts2 v2.1.8支援、JPA 2.0也支援,而這本書開頭就形容OSGi就是JVM上的SOA,SOA是通常用於Web,但有誰會認為可以用於JVM。而在本書的提示下,原來啊!Eclipse 3.x開始,底層就是OSGi實作出來的。 雖然以前就聽說了,但看了書中的展示,還是相當訝異。我用的是Eclipse 3.5,DOS切到Eclipse主目錄下的plugins子目錄,有個jar檔叫org.eclipse.org_3.5.0.v20090520.jar,格式其實是org.eclipse.org_{eclipse版本}.{年月日}.jar。執行如下: java –jar org.eclipse.org_3.5.0.v20090520.jar -console 就有osgi>提示的console,跑的就是Eclipse專用的Equinox。而若切到Eclipse主目錄,執行如下: eclipse.exe -console 會先osgi console視窗再出現Eclipse畫面,而當您在osgi>提示下輸入headers 0,就會發現Eclipse plugin其實都是OSGi形式的bundle釋出。我猜這也是Eclipse安裝新的plugin後不需要重啟就能更新的原因。OSGi就是可以讓插件在runtime下載入、更新和卸除而不妨礙正在運行的系統。 而除了Eclipse以外,BMW汽車應用控制系統也是使用OSGi作為嵌入式系統,證明了OSGi兼具輕巧與高效的性能。
Jemmy 發表在 痞客邦 留言(2) 人氣(69)
OSGi Framework在Open Source最著名的有四個,除了Oscar快三年沒有更新外,其餘分別是Equinox、Knopflerfish和Apache出來的Felix,此外也介紹一個不錯的簡體中文網站,http://www.open-open.com/index.htm,Java開源大全,目前是我見過最完整的絕世武功目錄。自http://felix.apache.org/site/index.html取得felix-1.2.1後解壓縮,啟動方式是進入install_dir後,執行java -jar bin/felix.jar就能進入prompt模式操作,而ps指令與Equinox的ss指令相同,列出所有services清單。其它可以參照help指令。 而Felix整合進Eclipse卻是最陽春的方式,把執行環境也給import進來:1. Create Java Project,名為Felix2. import felix目錄到Project,所以除了src、bin,還有bundle、conf與doc目錄以及一些NOTICE也被import進來。3. 按Project Name按左鍵選[Run As],透過Run Configurations設定要執行felix的Main程式,Eclipse會自動在bin底下找到felix.jar,選擇org.apache.felix.main.Main,然後按[Run],如此Console Tab就會出現prompt操作模式。 Jemmy 發表在 痞客邦 留言(0) 人氣(185)