連兩天打麻將,晚上就研究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了。這部份見下篇。