转载请保留作者信息:
作者:88250
Blog:http:/blog.csdn.net/DL88250
MSN & Gmail & QQ:DL88250@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);
}
* @(#)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();
}
* @(#)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;
}
}
* @(#)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());
}
}
* @(#)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;
}
}
* @(#)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(140, 1);
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;
}
}
}
* @(#)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(140, 1);
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组件服务模型
然后,进入KF的安装目录,启动我们的应用:
现在,我们只是脱离了KF的图形界面控制中心,在命令行下面启动的KF框架,并把SecondOSGi与SeondOSGiClient安装运行在KF框架里。一切的主动权还是在KF手里。
结合以前JavaEE的实践,JSP/Servlets,EJBs不都是被控制在容器(container)里的吗?
不过,话又说回来了,我希望自己的框架应用构建于OSGi之上,而不是之内。
之内的部分应该是可扩展的Plug-ins部分,让OSGi作为底层框架,为我们提供稳定的插件机制。
之外的部分应该是我们应用的框架,构建在OSGi之上。对OSGi做一个封装,就KF而言,就是封装它的命令接口,让我们的框架可以对插件随时安装、卸载、运行、停止、更新。。。。
当然,以上是个设想,学习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
-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第二天的设想。。。。
总之不足的地方很多,要把这个示例慢慢演化成正真具有价值的应用可能还需要一些时间。