連兩天打麻將,晚上就研究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比前者多些。先講前者:

  1. 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

  2. 在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"

  3. 程式碼(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似乎可以)。

  1. 在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

  2. 在MENIFEST.MF的設定:只需import javax.servlet和javax.servlet.http,另外需要加上:
    Require-Bundle: org.eclipse.equinox.http.registry
  3. 在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了。這部份見下篇。

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 Jemmy 的頭像
    Jemmy

    Jemmy Walker

    Jemmy 發表在 痞客邦 留言(0) 人氣()