使用NetBeans6开发OSGi应用(4)——Servlet与Http服务[88250原创]

转载请保留作者信息:

作者:88250

Bloghttp:/blog.csdn.net/DL88250

MSN & Gmail & QQDL88250@gmail.com


摘要

上一次,我们分析了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
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Library General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

package cn.edu.ynu.sei.osgiservlet;

import java.net.URL;
import java.util.Hashtable;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.knopflerfish.service.log.LogRef;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;
import org.osgi.service.http.HttpContext;
import org.osgi.service.http.HttpService;

/**
 * OSGi activator for <code>InfoServlet</code>.
 * 
@author 88250
 * 
@version 1.0.0.0, Mar 5, 2008
 */

public class Activator implements BundleActivator {

    
// This is my world
    static BundleContext bc;

    
static LogRef log;

    
static final String RES_ALIAS = "/";     // the http server root

    
static final String RES_DIR = "/www";  // bundle resource directory 

    
static final String SERVLET_ALIAS = "/servlet/firstservlet"; // a small servlet

    Hashtable registrations = 
new Hashtable();

    
public void start(BundleContext bc) throws BundleException {

        
this.bc = bc;
        
this.log = new LogRef(bc);

        ServiceListener listener = 
new ServiceListener() {

            
public void serviceChanged(ServiceEvent ev) {
                ServiceReference sr = ev.getServiceReference();

                
switch (ev.getType()) {
                    
case ServiceEvent.REGISTERED:
                        setRoot(sr);
                        
break;
                    
case ServiceEvent.UNREGISTERING:
                        unsetRoot(sr);
                        
break;
                }
            }
        };

        String filter = "(objectclass=" + HttpService.
class.getName() + ")";

        
try {
            bc.addServiceListener(listener, filter);

            ServiceReference[] srl = bc.getServiceReferences(
null, filter);
            
for (int i = 0; srl != null && i < srl.length; i++) {
                listener.serviceChanged(
new ServiceEvent(ServiceEvent.REGISTERED,
                                                         srl[i]));
            }
        } 
catch (Exception e) {
            log.error("Failed to set up listener for http service", e);
        }
    }

    
public void stop(BundleContext bc) throws BundleException {
    }

    
void setRoot(ServiceReference sr) {

        
if (registrations.containsKey(sr)) {
            
return// already done
        }

        log.info("set root for " + sr);

        HttpService http = (HttpService) bc.getService(sr);

        HttpContext context = 
new HttpContext() {

            
public boolean handleSecurity(HttpServletRequest request,
                                           HttpServletResponse response)
                    
throws java.io.IOException {
                
return true;
            }

            
public URL getResource(String name) {

                
// when registering the root, it seems
                // like we get no separator before the file.
                // Is that a bug?? Code below is a workaround      
                if (name.startsWith(RES_DIR) &&
                        name.length() > RES_DIR.length() &&
                        '/' != name.charAt(RES_DIR.length())) {
                    name = RES_DIR + "/" + name.substring(RES_DIR.length());
                }

                
// default to index.html
                if (name.equals(RES_DIR)) {
                    name = "/www/index.html";
                }

                
// and send the plain file
                URL url = getClass().getResource(name);

                
return url;
            }

            
public String getMimeType(String reqEntry) {
                
return null// server decides type
            }
        };

        
try {
            http.registerResources(RES_ALIAS, RES_DIR, context);
            http.registerServlet(SERVLET_ALIAS, 
new InfoServlet(sr),
                                 
new Hashtable(), context);

            registrations.put(sr, context);
        } 
catch (Exception e) {
            log.error("Failed to register resource", e);
        }
    }

    
void unsetRoot(ServiceReference sr) {
        
if (!registrations.containsKey(sr)) {
            
return// nothing to do
        }

        log.info("unset root for " + sr);

        HttpService http = (HttpService) bc.getService(sr);

        
if (http != null) {
            http.unregister(RES_ALIAS);
            http.unregister(SERVLET_ALIAS);
            bc.ungetService(sr);
        }
        registrations.remove(sr);
    }
}


/*
 * @(#)InfoServlet.java
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Library General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
*/
package cn.edu.ynu.sei.osgiservlet;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.osgi.framework.ServiceReference;

/**
 * The first OSGi servlet application.
 * 
@author 88250
 * 
@version 1.0.0.0, Mar 5, 2008
 
*/
public class InfoServlet extends HttpServlet {

    ServiceReference httpSR;

    
public InfoServlet(ServiceReference httpSR) {
        
this.httpSR = httpSR;
    }

    
public void doPost(HttpServletRequest request,
                        HttpServletResponse response)
            
throws ServletException,
                   IOException {
        
// Handle just as GET
        doGet(request, response);
    }

    
public void doGet(HttpServletRequest request,
                       HttpServletResponse response)
            
throws ServletException, IOException {

        PrintWriter out 
= response.getWriter();

        response.setContentType(
"text/html");

        out.println(
"<html>");
        out.println(
"<head>");
        out.println(
"<title>Demo</title>");
        out.println(
"I am a simple servlet base running in OSGi :-)");
        out.println(
"</head>");
        out.println(
"<body>");

        
try {
        } 
catch (Exception e) {
            out.println(
"<pre>");
            e.printStackTrace(out);
            out.println(
"</pre>");
        }

    }
}

还有一个简单的HTML页面(/www/index.html):
<html>
    
<head>
        
<title>The First OSGi Servlet Appication</title>
    
</head>
    
    
<body>
        
<h2>Test page for OSGi web server</h2>
        
<p>
            Hello OSGi Servlet
        
</p>
        
<script type="text/javascript">
        document. writeln(
"Test javascript!");
        
</script>
    
</body>
</html>

3. manifest.mf

Manifest-Version: 1.0
Bundle-ManifestVersion: 
2
Bundle-Name: OSGi Servlet
Bundle-SymbolicName: cn.edu.ynu.sei.osgiservlet
Bundle-Version: 
1.0.0.0
Bundle-Category: example
Bundle-Description: Demo HTTP servlet
Bundle-Activator: cn.edu.ynu.sei.osgiservlet.Activator
Import-Package: javax.servlet
,
 javax.servlet.http
,
 org.knopflerfish.service.log
,
 org.osgi.framework
,
 org.osgi.service.http

4. 测试

编译这个Bundle,安装它到KF里并运行之,结果如下图:

以地址 http://localhost:8080/servlet/firstservlet 访问我们的Servlet:


总结


本次,我们基于OSGi做了一个简单的HTTP/Servlet 容器,可以满足简单的应用。这样,我们可以把我们的应用统一在一个框架里,简化了很多技术细节。但是,做企业应用的话这样是远远不够的,我们也不是太有可能基于OSGi构建一个自己的Application Server,所以,只要容器支持OSGi,结合Spring DM是最好的选择。

posted on 2008-03-05 18:29  岚之山  阅读(170)  评论(0编辑  收藏  举报

导航