-
Notifications
You must be signed in to change notification settings - Fork 0
Felix_Tutorial_3
示例三 —— 辞典客户端软件包
这个示例程序创建了一个作为示例二中的辞典服务的客户端的程序包。在下面的代码中,我们的程序包使用其上下文环境来查询一个辞典服务。我们的客户端会使用它能够找到的第一个辞典服务,而且如果没有找到的话会将详细情况打印出来然後停止。使用一个OSGi服务就像使用Java接口一样,我们只需要将其类型转换为已知的辞典服务的接口。我们程序包的源代码在如下的名为Activator.java的文件中:
/*
- Apache Felix OSGi 教程. **/
package tutorial.example3;
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException;
import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference;
import tutorial.example2.service.DictionaryService;
/**
-
此类实现了一个以使用辞典服务检查一个词在辞典中是否存在的方法判断其是否拼写正确的程序包。
-
这个程序包会使用其找到的第一个服务,但不会去检查服务的变化情况(例如它不会去监听加入或
-
变更辞典服务的情况)。当此程序包启动时,这个线程会调用start()方法来从标准输入读取单词,
-
你可以输入一个空行来停止单词检查,但如果要重新开始单词检查必须停止然後重新启动此程序包。 / public class Activator implements BundleActivator { /
-
实现BundleActivator.start()方法。查询所有的辞典服务,
-
如果没有找到的话它只会简单地打印一条信息然後返回,否
-
则它会读取从标准输入读取单词并且检查在能找到的第一套
-
辞典里是否存在。
-
(注意: 在默认方法中进行这样冗长的业务流程并不是一个好的做法,
-
在这里写这样的代码只是教程需要)
-
@param context 程序包运行时在框架中所处的上下文环境 **/ public void start(BundleContext context) throws Exception { // 查询针对所有语言的服务。 ServiceReference[] refs = context.getServiceReferences( DictionaryService.class.getName(), "(Language=*)");
if (refs != null) { try { System.out.println("如要离开,请输入一个空行。"); BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); String word = "";
// Loop endlessly. while (true) { // 提示输入一个单词。 System.out.print("输入一个单词: "); word = in.readLine(); // 如果用户输入一个空行就退出循环。 if (word.length() == 0) { break; } // 首先,获取一个辞典服务然後检查单词是否正确。 DictionaryService dictionary = (DictionaryService) context.getService(refs[0]); if (dictionary.checkWord(word)) { System.out.println("Correct."); } else { System.out.println("Incorrect."); } // 放回辞典服务。 context.ungetService(refs[0]); } } catch (IOException ex) { }
} else { System.out.println("找不到任何辞典服务..."); } }
/**
- 实现BundleActivator.stop()方法。因为框架会自动放回所有正在使用的服务,
- 所以在这里不做任何事情。
- @param context 程序包运行时在框架中所处的上下文环境 **/ public void stop(BundleContext context) { // 注意: 服务会被自动释放。 } }
-
注意我们不需要在stop()方法中放回或释放服务,因为OSGi框架会自动为我们做这件事情。我们必须创建一个包含我们程序包的导引信息的manifest.mf文件,此描述文件包含如下内容:
Bundle-Name: Dictionary client Bundle-Description: A bundle that uses the dictionary service if it finds it at startup Bundle-Vendor: Apache Felix Bundle-Version: 1.0.0 Bundle-Activator: tutorial.example3.Activator Import-Package: org.osgi.framework, tutorial.example2.service
我们通过Bundle-Activator属性指定程序包接口,并且通过Import-Package指明我们的类引入了OSGi框架的核心包和辞典服务接口包。辞典服务接口包会部署在指明导出了此包的示例二中。OSGi框架会自动处理寻找这些要引入的包的一些细节情况。(提示:确信你的manifest文件尾部以回车结束,否则最后一行会被忽略)
为了编译这个源文件时我们需要在classpath中加入felix.jar文件(可以在felix套件的bin目录下找到),我们用下面的命令编译源文件:
javac -d c:\classes *.java
此命令会编译所有的源文件并且把生成的类文件输出到c:\classes目录中一个子目录下,这个子目录就是tutorial\example3,按照我们在源文件中制定的包名命名。为了让以上命令能够正常执行,目录c:\classes必须存在。编译后,我们必须创建一个JAR文件以包装生成的包目录,且要将包含软件包导引信息的描述文件一并添加到JAR包中。我们使用如下命令创建这个JAR文件:
jar cfm example3.jar manifest.mf -C c:\classes tutorial\example3
此命令利用我们创建的描述文件创建了一个JAR包而且包含了在c:\classes目录下的tutorial\example3目录中所有的类文件。当此JAR文件成功创建后,我们便可以准备安装并且启动此程序包。
我们按照usage.html中描述的步骤启动Felix,当我们启动Felix后,程序会询问一个档案名,我们可以将我们所有的程序包置入一个名为 "tutorial"的档案中。启动Felix後,我们要确信教程中描述的所有程序包除了示例二中的英语辞典服务程序包外都是停止的。我们可以使用Felix的 shell命令 -Y´ps¡获取所有程序包的列表,以及它们的状态和标记值。如果示例一中描述的程序包不是有效(activa)的,我们必须使用start命令和´ps¡命令打印出的那个标记值将其启动并且使用stop命令停掉所有其他在本教程中不需要的软件包。(注意: Felix使用一些程序包来提供命令行交互接口,所以不要把这些软件包停掉)现在我们可以安装并且启辞典服务程序包。假如我们的把我们的程序包创建在c:\tutorial。我们可以在Felix shell中使用如下方法将其安装并且启用:
start file:/c:/tutorial/example3.jar
上述命令可以在一个步骤里安装并启动这个软件包,同时也可以使用install和start两个命令分两步安装并启动此软件包。当我们启动软件包後,它会使用它会使用shell提示我们输入单词。这时如果想检查一个单词则将其输入如果想退出则可以直接输入一个空行。如果想要重新启动这个软件包,我们必须使用Felix shell中的ps命令获取此软件包的标识值,然後首先使用stop命令停掉这个软件包,然後使用start命令将其重新启动。想要测试这个辞典服务,可以输入辞典中的单词(例如´welcome¡、´to¡、´the¡、´OSGi¡、´tutorial¡),或者辞典中没有的单词。
这个客户端例子十分简单,而且实际上可以说过於简单。如果辞典服务突然间注销会发生什么情况呢?我们的客户端会在其尝试访问服务时抛出一个空指针异常。服务的动态可用性是OSGi服务模型的核心原则。所以,我们必须提高我们的客户端在处理这种问题时的´健壮性¡。在示例四中,我们会制作可以动态监控服务可用性的一个更复杂的辞典客户端。