使用NetBeans6开发OSGi应用(2)——SecondOSGi[88250原创]

转载请保留作者信息:

作者:88250

Bloghttp:/blog.csdn.net/DL88250

MSN & Gmail & QQDL88250@gmail.com


摘要

上一次,我们了解了OSGi的背景并使用NetBeans6,基于Knopflerfish(OSGi的一个RI) 完成了第一个OSGi应用——FirstOSGi。这一次,我们将对OSGi进行深入一点学习——SecondOSGi,让我们掌握Bundles之间的调用!

准备

上一次 :-)

开工:

1. 创建工程

打开NetBeans6 IDE,创建两个普通的Java App——SecondOSGi、SecondOSGiClient。把KF下的Sources拷贝到两个工程下(记得加入asm3.0的Jar):

        

在SecondOSGiClient工程的demo包下的两个Java文件(Demo.java, DemoFactory.java)与SecondOSGi工程demo包下的完全一样,这里是懒得发布编译好的class byte file给Client了,直接给的接口源文件。

2. 编写manifest.mf

把工程View切换到Files,改写manifest.mf如下:





关于manifest.mf里各种properties就不罗嗦了,有很多文档可以参考 :-)

3. 编写Activator

下面逐一给出源文件,一一对应上面工程结构图。

service提供者,即SecondOSGi工程下的:

/*
 * @(#)Demo.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 secondosgi.service.demo;


/**
 * A simple demo service.
 * 
@author 88250
 * 
@version 1.0.0.0, Feb 14, 2008
 
*/
public interface Demo {

    
/**
     * Add two integers and return the result.
     * 
@param a
     * 
@param b
     * 
@return 
     
*/
    
public int add(int a, int b);
}

/*
 * @(#)DemoFactory.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 secondosgi.service.demo;

/**
 * <b>Another</b> very simple demo service API.
 * <p>
 * The intentions of this interface class is to show that different bundles
 * will get different instances of a service, by the means of a 
 * ServiceFactory.
 * </p>
 * 
@author 88250
 * 
@version 1.0.0.0, Feb 14, 2008
 
*/
public interface DemoFactory {

    
/**
     * Say hello.
     
*/
    
void hello();
}

/*
 * @(#)DemoImpl.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 secondosgi.service.demo.impl;

import secondosgi.service.demo.Demo;

/**
 * Implementation of the Demo service.
 * 
@author 88250
 * 
@version 1.0.0.0, Feb 14, 2008
 
*/
public class DemoImpl implements Demo {

    
public int add(int a, int b) {
        
return a + b;
    }
}

/*
 * @(#)DemoFactoryImpl.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 secondosgi.service.demo.impl;

import secondosgi.service.demo.DemoFactory;
import org.osgi.framework.Bundle;

/**
 * Implementation of the DemoFactory service. The intentions of this
 * class is to show that different bundles will get different instances
 * of a service, by the means of a ServiceFactory.
 * 
@author 88250
 * 
@version 1.0.0.0, Feb 14, 2008
 
*/
public class DemoFactoryImpl implements DemoFactory {

    
private Bundle b;

    
/**
     * Constructor with argument.
     * 
@param b a <code>Bundle</code> 
     
*/
    
public DemoFactoryImpl(Bundle b) {
        
this.b = b;
    }

    
public void hello() {
        System.out.println(
"Hello bundle #" + b.getBundleId());
    }
}

很关键的Activator,实现服务的注册,注销:
/*
 * @(#)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 secondosgi.service.demo.impl;

import secondosgi.service.demo.Demo;
import secondosgi.service.demo.DemoFactory;
import java.util.Hashtable;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceFactory;
import org.osgi.framework.ServiceRegistration;

/**
 * Activator which creates and registers a Demo1 service.
 * 
@author 88250
 * 
@version 1.0.0.0, Feb 14, 2008
 
*/
public class Activator implements BundleActivator {

    
private Demo demo;

    
public void start(BundleContext bc) {
        System.out.println(
"start " + getClass().getName());
        demo 
= new DemoImpl();
        bc.registerService(Demo.
class.getName(),
                demo,
                
new Hashtable());

        
// Create a service factory for DemoFactory implementations
        ServiceFactory factory = new ServiceFactory() {

            Hashtable services 
= new Hashtable();
            
// Will get called when a bundle request a service
            @SuppressWarnings("unchecked")
            
public Object getService(Bundle b,
                    ServiceRegistration reg) {
                System.out.println(
"get from " + b.getBundleId());

                
// Create when necessary
                DemoFactory impl = (DemoFactory) services.get(b);
                
if (impl == null) {
                    impl 
= new DemoFactoryImpl(b);
                    services.put(b, impl);
                }
                
return impl;
            }

            
// will get called when a bundle ungets a service or stops
            public void ungetService(Bundle b,
                    ServiceRegistration reg,
                    Object service) {
                System.out.println(
"unget from " + b.getBundleId());
                services.remove(b);
            }
        };

        
// Note how factory only implements ServiceFactory, 
        
// but we still register as DemoFactory1 service
        bc.registerService(DemoFactory.class.getName(),
                factory,
                
new Hashtable());
    }

    
public void stop(BundleContext bc) {
        System.out.println(
"stop " + getClass().getName());

        demo 
= null;
    }
}

client角色,服务使用者,即SecondOSGiClient工程下的(Demo,DemoFactory两个接口同服务提供的)。
在这个Activator里,我们实现了服务的查找、调用、服务提供者状态的监听:
/*
 * @(#)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 secondosgi.service.client.impl;

import secondosgi.service.demo.Demo;
import secondosgi.service.demo.DemoFactory;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;

/**
 * Activator which registers a listener for, and test, any Demo service.
 * 
@author 88250
 * 
@version 1.0.0.0, Feb 14, 2008
 
*/
public class Activator implements BundleActivator, ServiceListener {

    
private static BundleContext bc;

    
private ServiceListener listener;

    
public void start(BundleContext bc) {
        System.out.println(
"start " + getClass().getName());
        Activator.bc 
= bc;

        
try {
            
// Filter that matches all Demo services
            String filter = "(objectclass=" + Demo.class.getName() + ")";

            
// Fetch all registered Demo services
            
// and test them manually
            ServiceReference[] srl =
                    bc.getServiceReferences(Demo.
class.getName(), filter);
            
for (int i = 0; srl != null && i < srl.length; i++) {
                testService(srl[i]);
            }

            
// ...and catch all newly registed ones too.
            bc.addServiceListener(listener, filter);
        } 
catch (Exception e) {
            
// sounds unlikely, but filter syntax errors are easy to write.
            e.printStackTrace();
        }

        testServiceFactory();
    }

    
void testServiceFactory() {
        
// Try to get a reference to the service produced by a factory
        ServiceReference factorySR = bc.getServiceReference(DemoFactory.class.getName());
        
if (factorySR != null) {
            DemoFactory df 
= (DemoFactory) bc.getService(factorySR);
            
if (df != null) {
                
// Different bundles will get different printouts
                df.hello();
            }
        }
    }

    
void testService(ServiceReference sr) {
        Demo demo 
= (Demo) bc.getService(sr);
        
int r = demo.add(1401);

        System.out.println(
"Testing " + demo + ", result=" + r);

        
// ..return the object to be nice
        bc.ungetService(sr);
    }

    
public void stop(BundleContext bc) {
        System.out.println(
"stop " + getClass().getName());
        Activator.bc 
= null;
    }

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

        
// just print some info and call testService() on
        
// all registered Demo services
        switch (event.getType()) {
            
case ServiceEvent.REGISTERED:
                System.out.println(
"Got Demo service");
                testService(sr);
                
break;
            
case ServiceEvent.UNREGISTERING:
                System.out.println(
"Lost Demo service");
                
break;
            
case ServiceEvent.MODIFIED:
                System.out.println(
"Modified Demo service");
                
break;
            
default:
                
break;
        }
    }
}

4. 测试

打开KF控制中心:

daniel@daniel-laptop:~/Work/knopflerfish_osgi_2.0.4/knopflerfish.org/osgi$ java -jar framework.jar 


打开构建好的SecondOSGi.jar以及SecondOSGiClient.jar,运行!



总结

这一次,我们对OSGi的了解更深了一步。

从设计的角度:一个可扩展的Service-Oriented组件服务模型

从开发的角度:我们发布接口给客户,实现了“针对接口编程”的OO核心实践

不足之处

我们一直都是在KF的控制台下启动的应用,如何做成独立的(standalone)可运行的Jar发布呢?

1. 在命令行下启动OSGi框架

首先,编写一个启动参数文件:secondosgi.xargs
-launch
-istart /home/daniel/Work/Sources/Java/SecondOSGi/dist/SecondOSGi.jar
-istart /home/daniel/Work/Sources/Java/SecondOSGiClient/dist/SecondOSGiClient.jar

然后,进入KF的安装目录,启动我们的应用:


现在,我们只是脱离了KF的图形界面控制中心,在命令行下面启动的KF框架,并把SecondOSGi与SeondOSGiClient安装运行在KF框架里。一切的主动权还是在KF手里。
结合以前JavaEE的实践,JSP/Servlets,EJBs不都是被控制在容器(container)里的吗?
不过,话又说回来了,我希望自己的框架应用构建于OSGi之上,而不是之内。
之内的部分应该是可扩展的Plug-ins部分,让OSGi作为底层框架,为我们提供稳定的插件机制。
之外的部分应该是我们应用的框架,构建在OSGi之上。对OSGi做一个封装,就KF而言,就是封装它的命令接口,让我们的框架可以对插件随时安装、卸载、运行、停止、更新。。。。
当然,以上是个设想,学习OSGi第二天的设想。。。。
总之不足的地方很多,要把这个示例慢慢演化成正真具有价值的应用可能还需要一些时间。

posted on 2008-02-14 21:02  岚之山  阅读(139)  评论(0编辑  收藏  举报

导航