Rebundle derby.jar

0

源起

應用程式總是需要地方放資料,這裡用的是 Apache Derby。因為文件提到支援 OSGi,原先預期可以直接使用,因為其內建 EmbeddedActivator,不過無法在 eclipse pde 環境載入,原因不明,於是轉包一個來用。

另一個原因是希望將 jar 包成一個,比較方便 export。

轉包

目前內容和 org.apache.derby.osgi.EmbeddedActivator 一樣如下,只是加個 MANIFEST.MF。

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: haha.derby
Bundle-SymbolicName: haha.derby
Bundle-Version: 1.0.0
Bundle-Localization: plugin
Bundle-ClassPath: lib/derby.jar,
 lib/derbytools.jar,
 .
Bundle-Activator: org.apache.derby.osgi.EmbeddedActivator
Import-Package: org.osgi.framework;version="1.4.0" 
Export-Package: org.apache.derby.jdbc

org.apache.derby.osgi.EmbeddedActivator

public final class EmbeddedActivator implements BundleActivator {

  public void start(BundleContext context) {
    new org.apache.derby.jdbc.EmbeddedDriver();
  }

  public void stop(BundleContext context) {
    try {
      DriverManager.getConnection("jdbc:derby:;shutdown=true");
    } catch (SQLException sqle) {
    }
  }
}

Network Server Mode

為了方便測試,將啟動改為 org.apache.derby.drda.NetworkServerControl 來負責, 啟動後預設將開啟 1527 port,可改用 org.apache.derby.jdbc.ClientDriver 來連線。

MANIFEST.MF

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: haha.derby
Bundle-SymbolicName: haha.derby
Bundle-Version: 1.0.0
Bundle-Localization: plugin
Bundle-ClassPath: .,
 lib/derbytools.jar,
 lib/derby.jar,
 lib/derbynet.jar,
 lib/derbyclient.jar
Bundle-Activator: haha.derby.DerbyActivator
Import-Package: org.osgi.framework;version="1.4.0" 
Export-Package: org.apache.derby.jdbc

src/haha/derby/DerbyActivator.java

public void start(BundleContext context) throws Exception {
  server = new NetworkServerControl();
  server.start(null);
}
public void stop(BundleContext context) throws Exception {
  server.shutdown();
}

分開比較方便

每個包都需要功能測試,這次想要將之前的 haha.remix.derby 分兩包, 一個是 haha.remix.derby.server 負責 derby.jar/derbynet.jar/jerbytools.jar, 另一個是 haha.remix.derby.client 負責 derbyclient.jar。

觀察

  1. 資料以檔案夾為單位,例如建立 derbyDB 的話,會建立 derbyDB 目錄來放資料。 沒有設定 derby.system.home 或是直接在 jdbc 中指明位置的話,大概會出現像 是 C:\Downloads\EclipseInstall\eclipse-3.2 當前執行程式的目錄下。

DWR service bundle

0

源起

前日將 dwr 2.0 與 domain object 兩種東西包在一起成為 HelloDwr bundle 來測試,這樣做當然非常方便,完全不用擔心 classloader 的問題,不過延展性就差一點,這次希望可以分離一個 DWR 2.0 service bundle 出來用,一來讓需要這個服務的 domain object bundle 方便取用,二來也可以不用每個 domain object bundle 都帶上自己的 dwr.jar。

之前的做法可以參考 HelloDwr bundle

dwr 自己載入 domain object 的方式與 OSGi 的期望的方式有所不同,為求支援這種 ContextClassLoader 機制,這裡 採取尚未成為 OSGi 標準的 Eclipse-BuddyPolicy 與 Eclipse-RegisterBuddy 做法,這種做法可以解決這類問題,後遺症是 這意味著這種 bundle 只能在 org.eclipse.osgi.jar 下執行,其他 OSGi 環境將不會支援。

http://eclipsezone.com/articles/eclipse-vms/

equinox osig 執行環境可以到下面連結下載,最好是 equinox osgi 3.3M3 或是比較新的 Integration Builds 來用,這樣才可以支援到 servlet 2.4。

http://download.eclipse.org/eclipse/equinox/

haha.dwrds

src/haha/dwrds/DwrDservice.java

輸出的服務介面,讓客端註冊那些物件要遠端存取。

package haha.dwrds;

public interface DwrDservice {
    public void register(String[] classNameArray);
}

MANIFEST.MF

除了輸出服務之外,還要表明 Eclipse-BuddyPolicy 說願意交朋友。

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: haha.dwrds
Bundle-SymbolicName: haha.dwrds
Bundle-Version: 1.0.0
Bundle-Localization: plugin
Import-Package: javax.servlet;version="2.4.0",
 javax.servlet.http;version="2.4.0",
 org.osgi.service.component;version="1.0.0",
 org.osgi.service.http;version="1.2.0",
 org.osgi.service.log;version="1.3.0" 
Bundle-ClassPath: lib/dwr.jar,.
Service-Component: OSGI-INF/service.xml
Export-Package: haha.dwrds,
 org.directwebremoting,
 org.directwebremoting.annotations
Eclipse-BuddyPolicy: registered

OSGI-INF/service.xml

這裡除了輸出服務之外,還綁上一些服務。

<?xml version="1.0" encoding="UTF-8"?>
<component name="dwrDserviceBind">
  <implementation class="haha.dwrds.DwrDserviceImpl"/>
  <service>
    <provide interface="haha.dwrds.DwrDservice"/>
  </service>
  <reference name="LOG" interface="org.osgi.service.log.LogService" 
    cardinality="1..1" bind="setLog" unbind="unsetLog" policy="static"/>
  <reference name="HTTP" interface="org.osgi.service.http.HttpService" 
    cardinality="1..1" policy="dynamic" bind="setHttp" unbind="unsetHttp"/>
</component>

src/haha/dwrds/DwrDserviceImpl.java 除了實做註冊之外,主要提供綁定的功能, 至於動態註冊物件到 dwr 的方式是採用修改 init-param 的土法,然後在將這個 DwrServlet 註冊到 HttpService 去。

為了測試方便,這個 bundle 自己內建兩個物件,會先在注入到 dwr 中使用。

haha.hello

src/haha/FooBean.java

package haha.hello;

import org.directwebremoting.annotations.RemoteMethod;
import org.directwebremoting.annotations.RemoteProxy;

@RemoteProxy
public class FooBean {

    @RemoteMethod
    public int getFoo(){
        return 999;
    }
}

MANIFEST.MF

除了匯入 haha.dwrds 服務之外,還要表明 Eclipse-RegisterBuddy 說和 haha.dwrds 是麻吉。

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: haha.hello
Bundle-SymbolicName: haha.hello
Bundle-Version: 1.0.0
Bundle-Localization: plugin
Import-Package: haha.dwrds,
 org.directwebremoting.annotations,
 org.osgi.service.component;version="1.0.0",
 org.osgi.service.log;version="1.3.0" 
Service-Component: OSGI-INF/reference.xml
Eclipse-RegisterBuddy: haha.dwrds

OSGI-INF/reference.xml

<?xml version="1.0" encoding="UTF-8"?>
<component name="haha.hello.Component">
  <implementation class="haha.hello.Component"/>
  <reference name="LOG" interface="org.osgi.service.log.LogService" 
       cardinality="1..1" bind="setLog" unbind="unsetLog" policy="static"/>
  <reference name="DWR" interface="haha.dwrds.DwrDservice" 
       cardinality="1..1" policy="static" bind="setDwr" unbind="unsetDwr" />
</component>

src/haha/hello/Component.java

protected void activate(ComponentContext context) {
  log.log(LogService.LOG_INFO, "### active hello dwr");
  dwrDservice.register(
      new String[]{  FooBean.class.getCanonicalName(), 
      FooBean2.class.getCanonicalName()});
}

測試 test

開瀏覽器到 http://localhost/dwr 應該可以看到四個物件,試著在 haha.hello 專案中對遠端輸出物件新增,刪除或是改名看看。

下載 download

dwrservice_bundle_20061031.zip

觀察

  1. 這些牽涉到 ContextClassLoader 議題的現有 lib 要轉包 bundle,做法到底是分開還是合在一起客有利弊,如果很單純的應用,也許直接包還比較方便。
  2. 也許過不久會有類似的 bundle 出來,就不用自己包。
  3. eclipse 為了實際應用,開發出很多 OSGi 還沒定義到的功能,會不會轉 R5 規格,有待觀察,問題是規格過之前,這類問題還是需要解決方案,eclipse 這方面已有不錯的應用。

HelloDwr bundle

0

源起

想要測試一下 DWR 的功能,為了方便,這個例子是用 DWR2 來測的。

http://getahead.ltd.uk/dwr/getstarted http://getahead.ltd.uk/dwr/server/annotations

建議與 HelloJsp Bundle 交互參考。

src/haha/Component.java

這個物件將使用 LogService 與 HttpService 做一些設定,把原本 WEB-INF/web.xml 的設定改成直接註冊到 HttpService 的做法。

另外一個需要的設定檔的 WEB-INF/dwr.xml 採用 annotation 可以放到 src/haha/HeheBean.java 原始碼中間去,省掉 dwr.xml 檔案載入問題。

....
DwrServlet dwrServlet = new DwrServlet();
Hashtable initparams = new Hashtable();
initparams.put("debug", "true");
initparams.put("classes", HeheBean.class.getCanonicalName());
httpService.registerServlet("/dwr", dwrServlet, initparams,commonContext);
....

src/haha/HeheBean.java

要遠端存取的物件。

package haha;

import org.directwebremoting.annotations.Create;
import org.directwebremoting.annotations.RemoteMethod;

@Create
public class HeheBean {

    private String name;

    @RemoteMethod
    public int getFoo(){
        return 43;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

osgi console

osgi> ss

Framework is launched.

id    State       Bundle
0    ACTIVE      system.bundle_3.3.0.v20061023
1    ACTIVE      HelloDwr_1.0.0
2    ACTIVE      javax.servlet_2.4.0.200609281713
3    ACTIVE      org.apache.commons.logging_1.0.4
4    ACTIVE      org.eclipse.equinox.ds_1.0.0.v20060828
5    ACTIVE      org.eclipse.equinox.http.jetty_1.0.0.v20061012
6    ACTIVE      org.eclipse.equinox.http.servlet_1.0.0.v20061023
7    ACTIVE      org.eclipse.equinox.log_1.0.100.v20060717
8    ACTIVE      org.eclipse.osgi.services_3.1.100.v20060918
9    ACTIVE      org.mortbay.jetty_5.1.11.200609281713

開瀏覽器到 http://localhost/index.html 測看看,也可以改點東西玩看看,只要改完在 console 輸入 update 1 就會生效。

Download

為了方便測試,將所有需要的 bundle 包一起,同時還有 HelloDwr 的原始碼,有需要的人可以用 eclipse 3.2 玩看看。

HelloDwr and osgi target platform

觀察

  1. 目前只有 hello 一下,看一下 debug 輸出,沒有測到太多部份。
  2. 試圖將 dwr 獨立成可重複使用的 bundle,沒有成功,因為 dwr 運作時需要載入 HeheBean.class 來讀取 annotation,如何將 HeheBean 變成服務反注入 dwr 還有待練習。

hellojsp bundle

0

源起

試著完成一個簡易的 JSP bundle,然後跑在 OSGi 的平台上。

要測前先看看之前的環境設定,先確定可以跑起來。

Hello OSGi JSP examples

Hello OSGi Servlet

hellojsp project

到 eclipse 建立一個純 OSGi 的 Plugin project,最後 export 成為 jar 即可。

  1. META-INF/MANIFEST.MF
  2. OSGI-INF/component.xml
  3. src/hello/Component.java
  4. build.properties
  5. web/index.html
  6. web/hello.jsp

MANIFEST.MF

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: HelloJsp Plug-in
Bundle-SymbolicName: HelloJsp
Bundle-Version: 1.0.0
Bundle-Localization: plugin
Import-Package: javax.servlet;version="2.4.0",
 org.eclipse.equinox.jsp.jasper,
 org.osgi.framework;version="1.4.0",
 org.osgi.service.component;version="1.0.0",
 org.osgi.service.http;version="1.2.0",
 org.osgi.service.log;version="1.3.0" 
Service-Component: OSGI-INF/component.xml

component.xml

<?xml version="1.0" encoding="UTF-8"?>
<component name="hello.component">
  <implementation class="hello.Component"/>
  <reference name="LOG" 
    interface="org.osgi.service.log.LogService" 
    cardinality="1..1" 
    bind="setLog" unbind="unsetLog" 
    policy="static"/>
  <reference name="HTTP" 
    interface="org.osgi.service.http.HttpService" 
    cardinality="1..1" 
    policy="dynamic" 
    bind="setHttp" 
    unbind="unsetHttp"/>
</component>

src/hello/Component.java

package hello;

import javax.servlet.Servlet;
import javax.servlet.ServletException;
import org.eclipse.equinox.jsp.jasper.ContextPathServletAdaptor;
import org.eclipse.equinox.jsp.jasper.JspServlet;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.http.HttpContext;
import org.osgi.service.http.HttpService;
import org.osgi.service.http.NamespaceException;
import org.osgi.service.log.LogService;

public class Component {

    LogService log;
    HttpService httpService;
    static final String ROOT = "/web";

    protected void activate(ComponentContext context) {

        log.log(LogService.LOG_INFO, "active hello.Component");
        HttpContext commonContext = this.httpService.createDefaultHttpContext();

        JspServlet jspServlet = new JspServlet(context.getBundleContext()
                .getBundle(), ROOT);

        Servlet adaptedJspServlet = new ContextPathServletAdaptor(jspServlet,
                "/", ROOT);
        try {
            httpService.registerResources("/", ROOT, commonContext);
            httpService.registerServlet("/*.jsp", 
                            adaptedJspServlet, null, commonContext);            
        } catch (NamespaceException ne) {
            log.log(LogService.LOG_ERROR, ne.getMessage());
        } catch (ServletException se) {
            log.log(LogService.LOG_ERROR, se.getMessage());
        }
    }

    protected void deactivate(ComponentContext context) {
        log.log(LogService.LOG_INFO, "deactive hello.Component");

    }

    protected void setLog(LogService logService) {
        this.log = logService;

    }

    protected void unsetLog(LogService logService) {
        this.log = null;
    }

    protected void setHttp(HttpService httpService) {
        this.httpService = httpService;
    }

    protected void unsetHttp(HttpService httpService) {
        this.httpService.unregister("/");
        this.httpService.unregister("/*.jsp");
        this.httpService = null;
    }

}

build.properties

source.. = src/
output.. = bin/
bin.includes = META-INF/,\
               .,\
               OSGI-INF/,\
               web/

OSGi console

Framework is launched.

id    State       Bundle
0    ACTIVE      system.bundle_3.3.0.v20061023
27    ACTIVE      javax.servlet.jsp_2.0.0.200610251427
28    ACTIVE      org.apache.commons.el_1.0.0
29    ACTIVE      org.apache.jasper_5.5.17.200610251427
37    ACTIVE      org.eclipse.equinox.jsp.jasper_1.0.0.200610251427
38    ACTIVE      org.eclipse.equinox.jsp.jstl_1.0.0
40    ACTIVE      javax.servlet_2.4.0.200609281713
41    ACTIVE      org.apache.commons.logging_1.0.4
42    ACTIVE      org.eclipse.equinox.ds_1.0.0.v20060828
43    ACTIVE      org.eclipse.equinox.http.jetty_1.0.0.v20061012
44    ACTIVE      org.eclipse.equinox.http.servlet_1.0.0.v20061023
47    ACTIVE      org.eclipse.equinox.log_1.0.100.v20060717
48    ACTIVE      org.eclipse.osgi.services_3.1.100.v20060918
49    ACTIVE      org.mortbay.jetty_5.1.11.200609281713
51    ACTIVE      HelloJsp_1.0.0

測試

因為資源映射到 web 目錄下,所以直接用下面連結可以測試。

http://localhost/index.html

http://localhost/hello.jsp

觀察

  1. log service 改用 setXX/unsetXX 方式比較直覺,不需要再去找,OSGi 可以確保 active 到 deactive 之間這些服務運作正常。

hello osgi jsp example

0

源起

OSGi 的 HttpService 只提供 servlet 與靜態 resource 註冊,並不提供 JSP,同時 OSGi 定義只到 Servlet API 2.1 版本,如果需要支援 JSP 等標準,就必須另外掛一些 bundle 上去。

一開始需要下載 OSGi 的環境來用。

http://www.eclipse.org/equinox/

HTTP Service (Servlet 2.4 API)

目前還未正式釋出,可以用 eclipse 3.2 team project 匯入來使用,真正要用時再直接匯出成 jar 即可。根據 maillist 的說法,可能會在 3.3M3 釋出,到時就可以直接拿來用。

Embedding an HTTP server in Equinox

http://www.eclipse.org/equinox/server/http_in_equinox.php

http://www.eclipse.org/equinox/server/downloads/jettyhttp-anon.psf

HTTP Service 的實做變成 org.eclipse.equinox.http.jetty,設計方式為轉接 HTTP Service 介面到 jetty 的介面,就可以讓 OSGi 環境使用。

因為 jetty 緣故,所以可以提供 Servlet 2.4 支援,不過需要支援的相依 jar 會比較多。

osgi> 2006/10/26 上午 11:32:58 org.mortbay.http.HttpServer doStart
資訊: Version Jetty/5.1.x
2006/10/26 上午 11:32:58 org.mortbay.util.Container start
資訊: Started org.mortbay.jetty.servlet.ServletHandler@12558d6
2006/10/26 上午 11:32:58 org.mortbay.util.Container start
資訊: Started HttpContext[/,/]
2006/10/26 上午 11:32:58 org.mortbay.http.SocketListener start
資訊: Started SocketListener on 0.0.0.0:80
2006/10/26 上午 11:32:58 org.mortbay.util.Container start
資訊: Started org.mortbay.http.HttpServer@1e859c0

osgi> ss

Framework is launched.

id    State       Bundle
0    ACTIVE      system.bundle_3.3.0.v20060919
4    ACTIVE      org.eclipse.equinox.ds_1.0.0.v20060828
7    ACTIVE      org.eclipse.equinox.log_1.0.100.v20060717
8    ACTIVE      org.eclipse.osgi.services_3.1.100.v20060918
14    ACTIVE      javax.servlet_2.4.0.200610251415
15    ACTIVE      org.apache.commons.logging_1.0.4.200610251415
16    ACTIVE      org.eclipse.equinox.http.jetty_1.0.0.200610251415
17    ACTIVE      org.eclipse.equinox.http.servlet_1.0.0.200610251415
18    ACTIVE      org.mortbay.jetty_5.1.11.200610251415

JSP

一樣用 team projext 匯入。根據 maillist 的說法,可能會在 3.3M4 釋出,到時就可以直接拿來用。

OSGi based JSP Support

http://www.eclipse.org/equinox/server/jsp_support.php

http://www.eclipse.org/equinox/server/downloads/jspsupport-anon.psf

Framework is launched.

id    State       Bundle
0    ACTIVE      system.bundle_3.3.0.v20060919
4    ACTIVE      org.eclipse.equinox.ds_1.0.0.v20060828
7    ACTIVE      org.eclipse.equinox.log_1.0.100.v20060717
8    ACTIVE      org.eclipse.osgi.services_3.1.100.v20060918
14    ACTIVE      javax.servlet_2.4.0.200610251415
15    ACTIVE      org.apache.commons.logging_1.0.4.200610251415
16    ACTIVE      org.eclipse.equinox.http.jetty_1.0.0.200610251415
17    ACTIVE      org.eclipse.equinox.http.servlet_1.0.0.200610251415
18    ACTIVE      org.mortbay.jetty_5.1.11.200610251415
27    ACTIVE      javax.servlet.jsp_2.0.0.200610251427
28    ACTIVE      org.apache.commons.el_1.0.0
29    ACTIVE      org.apache.jasper_5.5.17.200610251427
30    ACTIVE      org.eclipse.equinox.jsp.examples_1.0.0
31    ACTIVE      org.eclipse.equinox.jsp.jasper_1.0.0.qualifier
32    ACTIVE      org.eclipse.equinox.jsp.jstl_1.0.0
33    ACTIVE      org.eclipse.equinox.jsp.jstl.examples_1.0.0

The jsp/jstl examples can be found at :

http://localhost/jsp-examples/index.html

http://localhost/jstl-examples/index.html

心得

  1. OSGi 的應用慢慢移到 server-side 和 eclipse 的這些年應用推廣很有關係,目前來看,開發一個 Bundle 最方便的方式還是開 eclipse 來用,雖然它的 PDE 環境還不是完整地支援 OSGi 開發,但是應會慢慢變的更完整。就馬上要用的需求來說,eclipse 的 PDE 環境算是十分方便,這點還沒在其開發環境看到。
  2. 類似 OSGi 的環境猜想應早就有人做過,只是沒到臨界點無法流行,目前 OSGi 有 eclipse IDE 這類比較大的用戶基礎來支撐,可以不斷演進與除錯,這點對於微型應用開發者來說,還蠻重要的。

Older posts: 1 2