使用NetBeans6开发OSGi应用(4)——Servlet与Http服务[88250原创]
转载请保留作者信息:
作者:88250
Blog:http:/blog.****.net/DL88250
MSN & Gmail & QQ:[email protected]
摘要
上一次,我们分析了KF(Knopflerfish)框架的设计,实践了基于OSGi的应用程序框架的设计。这一讲,我们将基于KF实现的OSGi规范Http Service,做一个简单的Servlet结合HTML/Javascript的实践。关于基于OSGi的Web开发
在开始前,我们先看一下一些关于OSGi在Web应用方面的尝试。开发Web应用,最重要的要属Web Server了(亦或Application Server)。在Server的厂商中 IBM、BEA和JBoss应用服务器采用OSGi,虽然目前我们的主要任务的做应用,但是可以了解这些最基本的东西。
好了,简要说一下OSGi在Web上的开发方式:
1. 将Web Server作为Bundle插入OSGi
目前,Apache Jetty可以做到。使用Spring DM(Spring-OSGi)的话,Tomcat的OSGi整合在未来应该也可以做。参考 这个2. 在Web Server内使用OSGi的Bundle
在Web容器里使用Spring DM(Spring-OSGi)可以做到。目前来说
在Java的Web开发上,Spring Framework是首选,但是如果应用是以OSGi作为底层的话,情况就不同了:1. 使用Spring,从Web应用开发的角度来说,视图/持久化/事务管理方便,可结合其他框架或技术的选择余地大
2. 使用OSGi,从系统整体开发角度来说,扩展性、维护性超好,系统整体结构清晰,可以把商业/控制逻辑做到很优良的组件话
3. 结合这两者使用的话(Spring DM),支持的扩展有限且技术相当复杂,得不偿失
所以,权衡后,我更偏向与直接使用OSGi来做Web应用,因为现在手头的一个项目只是运用例简单的HTML,AJAX与Servlet。
让我们简单实践一下!
准备
同上一次 :-)开工:
1. 创建工程
打开NB6,创建一个普通Java应用工程——OSGiServlet:注意,www文件夹是存放HTML源文件的地方,要直接放在src文件夹下。然后要导入3个Jar libs:
http_all-2.0.0.jar: OSGi 的 http service实现
knopflerfish-osgi.jar: 基本OSGi实现
servlet-api.jar: Sun的servlet实现
2.编写Activator与Servlet类
/*
*@(#)Activator.java
*
*Thisprogramisfreesoftware;youcanredistributeitand/ormodify
*itunderthetermsoftheGNUGeneralPublicLicenseaspublishedby
*theFreeSoftwareFoundation;eitherversion3oftheLicense,or
*(atyouroption)anylaterversion.
*
*Thisprogramisdistributedinthehopethatitwillbeuseful,
*butWITHOUTANYWARRANTY;withouteventheimpliedwarrantyof
*MERCHANTABILITYorFITNESSFORAPARTICULARPURPOSE.Seethe
*GNULibraryGeneralPublicLicenseformoredetails.
*
*YoushouldhavereceivedacopyoftheGNUGeneralPublicLicense
*alongwiththisprogram;ifnot,writetotheFreeSoftware
*Foundation,Inc.,59TemplePlace-Suite330,Boston,MA02111-1307,USA.
*/
packagecn.edu.ynu.sei.osgiservlet;
importjava.net.URL;
importjava.util.Hashtable;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importorg.knopflerfish.service.log.LogRef;
importorg.osgi.framework.BundleActivator;
importorg.osgi.framework.BundleContext;
importorg.osgi.framework.BundleException;
importorg.osgi.framework.ServiceEvent;
importorg.osgi.framework.ServiceListener;
importorg.osgi.framework.ServiceReference;
importorg.osgi.service.http.HttpContext;
importorg.osgi.service.http.HttpService;
/**
*OSGiactivatorfor<code>InfoServlet</code>.
*@author88250
*@version1.0.0.0,Mar5,2008
*/
publicclassActivatorimplementsBundleActivator{
//Thisismyworld
staticBundleContextbc;
staticLogReflog;
staticfinalStringRES_ALIAS="/";//thehttpserverroot
staticfinalStringRES_DIR="/www";//bundleresourcedirectory
staticfinalStringSERVLET_ALIAS="/servlet/firstservlet";//asmallservlet
Hashtableregistrations=newHashtable();
publicvoidstart(BundleContextbc)throwsBundleException{
this.bc=bc;
this.log=newLogRef(bc);
ServiceListenerlistener=newServiceListener(){
publicvoidserviceChanged(ServiceEventev){
ServiceReferencesr=ev.getServiceReference();
switch(ev.getType()){
caseServiceEvent.REGISTERED:
setRoot(sr);
break;
caseServiceEvent.UNREGISTERING:
unsetRoot(sr);
break;
}
}
};
Stringfilter="(objectclass="+HttpService.class.getName()+")";
try{
bc.addServiceListener(listener,filter);
ServiceReference[]srl=bc.getServiceReferences(null,filter);
for(inti=0;srl!=null&&i<srl.length;i++){
listener.serviceChanged(newServiceEvent(ServiceEvent.REGISTERED,
srl[i]));
}
}catch(Exceptione){
log.error("Failedtosetuplistenerforhttpservice",e);
}
}
publicvoidstop(BundleContextbc)throwsBundleException{
}
voidsetRoot(ServiceReferencesr){
if(registrations.containsKey(sr)){
return;//alreadydone
}
log.info("setrootfor"+sr);
HttpServicehttp=(HttpService)bc.getService(sr);
HttpContextcontext=newHttpContext(){
publicbooleanhandleSecurity(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsjava.io.IOException{
returntrue;
}
publicURLgetResource(Stringname){
//whenregisteringtheroot,itseems
//likewegetnoseparatorbeforethefile.
//Isthatabug??Codebelowisaworkaround
if(name.startsWith(RES_DIR)&&
name.length()>RES_DIR.length()&&
'/'!=name.charAt(RES_DIR.length())){
name=RES_DIR+"/"+name.substring(RES_DIR.length());
}
//defaulttoindex.html
if(name.equals(RES_DIR)){
name="/www/index.html";
}
//andsendtheplainfile
URLurl=getClass().getResource(name);
returnurl;
}
publicStringgetMimeType(StringreqEntry){
returnnull;//serverdecidestype
}
};
try{
http.registerResources(RES_ALIAS,RES_DIR,context);
http.registerServlet(SERVLET_ALIAS,newInfoServlet(sr),
newHashtable(),context);
registrations.put(sr,context);
}catch(Exceptione){
log.error("Failedtoregisterresource",e);
}
}
voidunsetRoot(ServiceReferencesr){
if(!registrations.containsKey(sr)){
return;//nothingtodo
}
log.info("unsetrootfor"+sr);
HttpServicehttp=(HttpService)bc.getService(sr);
if(http!=null){
http.unregister(RES_ALIAS);
http.unregister(SERVLET_ALIAS);
bc.ungetService(sr);
}
registrations.remove(sr);
}
}
*@(#)InfoServlet.java
*
*Thisprogramisfreesoftware;youcanredistributeitand/ormodify
*itunderthetermsoftheGNUGeneralPublicLicenseaspublishedby
*theFreeSoftwareFoundation;eitherversion3oftheLicense,or
*(atyouroption)anylaterversion.
*
*Thisprogramisdistributedinthehopethatitwillbeuseful,
*butWITHOUTANYWARRANTY;withouteventheimpliedwarrantyof
*MERCHANTABILITYorFITNESSFORAPARTICULARPURPOSE.Seethe
*GNULibraryGeneralPublicLicenseformoredetails.
*
*YoushouldhavereceivedacopyoftheGNUGeneralPublicLicense
*alongwiththisprogram;ifnot,writetotheFreeSoftware
*Foundation,Inc.,59TemplePlace-Suite330,Boston,MA02111-1307,USA.
*/
packagecn.edu.ynu.sei.osgiservlet;
importjava.io.IOException;
importjava.io.PrintWriter;
importjavax.servlet.ServletException;
importjavax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importorg.osgi.framework.ServiceReference;
/**
*ThefirstOSGiservletapplication.
*@author88250
*@version1.0.0.0,Mar5,2008
*/
publicclassInfoServletextendsHttpServlet{
ServiceReferencehttpSR;
publicInfoServlet(ServiceReferencehttpSR){
this.httpSR=httpSR;
}
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,
IOException{
//HandlejustasGET
doGet(request,response);
}
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsServletException,IOException{
PrintWriterout=response.getWriter();
response.setContentType("text/html");
out.println("<html>");
out.println("<head>");
out.println("<title>Demo</title>");
out.println("IamasimpleservletbaserunninginOSGi:-)");
out.println("</head>");
out.println("<body>");
try{
}catch(Exceptione){
out.println("<pre>");
e.printStackTrace(out);
out.println("</pre>");
}
}
}
还有一个简单的HTML页面(/www/index.html):
<head>
<title>TheFirstOSGiServletAppication</title>
</head>
<body>
<h2>TestpageforOSGiwebserver</h2>
<p>
HelloOSGiServlet
</p>
<scripttype="text/javascript">
document.writeln("Testjavascript!");
</script>
</body>
</html>
3. manifest.mf
4. 测试
编译这个Bundle,安装它到KF里并运行之,结果如下图:以地址 http://localhost:8080/servlet/firstservlet 访问我们的Servlet:
总结
本次,我们基于OSGi做了一个简单的HTTP/Servlet 容器,可以满足简单的应用。这样,我们可以把我们的应用统一在一个框架里,简化了很多技术细节。但是,做企业应用的话这样是远远不够的,我们也不是太有可能基于OSGi构建一个自己的Application Server,所以,只要容器支持OSGi,结合Spring DM是最好的选择。