Spring-driven or OSGi-standard HttpService

0

源起

原來的 OSGi HtppService 是個相當簡潔的介面,不提供太多細部的設定考量,也就是說整個 HttpService 的某些特質取決於底層的實做預設值,並不能在註冊時加以調整。

舉 welcome file 的例子來說,不同實做,出現的行為是 404/500 都不確定,太粗的介面提供小型裝置的容易實現性,但是對習慣開發 server-side 的開發者而言,實在不方便。

equinox 用 jetty 當 servlet 2.4 實做,jetty 5 是個成熟的實做,許多企業級應用都可找到,equinox 採用 ProxyServlet 轉接方式,來轉出符合 OSGi HttpService 的介面。

這裡不去修改這個 ProxyServlet 機制,而是動手另外實做類似 org.eclipse.equinox.http.jetty 的 Spring-driven HttpService 功能,同時轉用 jetty 6.1 來測試,這裡用 haha.remix.jetty 來包一大包,另外用 haha.hello.jetty 來啟動 jetty server,用 haha.hello.httpdoc 來註冊 http://localhost/。

haha.remix.jetty

不需啟動,基本上是個 lib 為主的 bundle。

META-IMF/MANIFEST.MF

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Jetty Plug-in
Bundle-SymbolicName: haha.remix.jetty
Bundle-Version: 6.1.0
Bundle-Localization: plugin
Import-Package: org.osgi.framework;version="1.3.0" 
Bundle-ClassPath: .,
 lib/jetty-6.1.0pre2.jar,
 lib/jetty-util-6.1.0pre2.jar,
 lib/servlet-api-2.5-6.1.0pre2.jar
Export-Package: javax.servlet;version="2.5.0",
 javax.servlet.http;version="2.5.0",
 javax.servlet.resources;version="2.5.0",
 org.mortbay.component,
 org.mortbay.io,
 org.mortbay.io.bio,....[SKIP]

haha.hello.jetty

META-IMF/MANIFEST.MF

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: haha.hello.jetty
Bundle-SymbolicName: haha.hello.jetty
Bundle-Version: 1.0.0
Bundle-Localization: plugin
Import-Package: org.osgi.framework;version="1.3.0" 
Require-Bundle: haha.remix.spring,
 haha.remix.jetty
Bundle-ClassPath: .
Export-Package: haha.hello.jetty

將 jetty 用 osgi-service 註冊到 OSGi 環境去。

MEAT-INF/spring/jetty-beans.xml

<bean id="httpServiceImpl" 
  class="haha.hello.jetty.HttpServiceImpl" 
 init-method="init" destroy-method="destroy">
  <property name="port" value="80" />
  <property name="debugEnable" value="true" />
</bean>
<osgi:service ref="httpServiceImpl" interface="haha.hello.jetty.HttpService"/>

haha.hello.jetty.HttpService

public interface HttpService {
  void addWebApp(URL fileURL, String contextPath);
}

haha.hello.httpdoc

這是比較麻煩的地方,主要是轉換檔案位置的問題,這裡用到 org.eclipse.equinox.common 的支援, 使用 org.eclipse.core.runtime.FileLocator 來轉檔案的位置給 haha.hello.jetty 知道。

META-IMF/MANIFEST.MF

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: haha.hello.httpdoc
Bundle-SymbolicName: haha.hello.httpdoc
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.framework;version="1.3.0",
 org.osgi.service.component;version="1.0.0",
 org.osgi.service.log;version="1.3.0",
 org.springframework.osgi.context
Require-Bundle: org.eclipse.equinox.common,
 haha.hello.jetty

將目錄所在用 osgi-reference 註冊到 jetty 環境去。

MEAT-INF/spring/httpdoc-beans.xml

<osgi:reference id="httpService" 
  interface="haha.hello.jetty.HttpService" />

<bean id="register" 
  class="haha.hello.httpdoc.Register" init-method="init" 
  destroy-method="destroy">
  <property name="httpService" ref="httpService" />
</bean>

haha.hello.httpdoc.Register 須實做 BundleContextAware 讓 Spring-OSGi 注入 BundleContext 來用。

public class Register implements BundleContextAware{

 private HttpService httpService;
 private BundleContext bundleContext;

 public void init() throws IOException{
  Bundle bundle = bundleContext.getBundle();
  URL entry = bundle.getEntry("htdoc");
  URL dir = FileLocator.toFileURL(entry);
  httpService.addWebApp(dir, "/");
 }

結果可以在 http://localhost/ 看到 haha.hello.httpdoc bundle 中的 htdoc 目錄。

Refactoring

為了減少重複寫這些註冊 Register 以及依賴 org.eclipse.equinox.common 與 org.springframework.osgi.context.BundleContextAware,將這個責任移到 haha.hello.jetty 去,客端只要負責實體化並注入 HttpService 即可,如下面情形。

<bean id="register" 
    class="haha.hello.jetty.Register" init-method="init" destroy-method="destroy">
    <property name="httpService" ref="httpService" />
    <property name="webappDir" value="htdoc" />
    <property name="contextPath" value="/project" />
</bean>    

觀察

  1. 簡單測試目錄註冊方式與整個 Spring-driven HttpService 的可用性,如果 htdoc 包成 jar 的話,還需要再進一步修改與考量。
  2. spring-driven jetty 也可以支援 osgi-standard http service interface,不過這裡沒有實做。
  3. 目前只有實做簡單的註冊,接下來可以考慮測看看 jsp/servlet/spring-mvc 等機制。
  4. 目前註冊端需要依賴 org.eclipse.equinox.common 與 org.springframework.osgi.context.BundleContextAware [參照 Refactoring 一節,移該責任到 jetty 啟動包去]
  5. 捨棄 OSGi 的 HttpService 代表已偏離標準的約定,這樣一來就需考量與其他 HttpService 實做相容議題。
  6. 大量採用 remix 的做法會形成大者恆大的現象,幾個巨大 bundle 會讓更新下載時間拉長, 只是部份更新卻需要下載數 MB,這點副作用要考慮。

Comments

(leave url/email »)

   Preview comment