-
Notifications
You must be signed in to change notification settings - Fork 0
Felix_Tutorial_5
示例五 —— 带有服务追踪器的辞典客户端程序包
在示例四中,我们为我们的词典服务创建了一个更可靠的客户端。因动态服务可用性的情况复杂,客户端的处理范围极有可能没有涵盖所有的状况。为了处理这种复杂情况,OSGi联盟在2001年重新将服务追踪器(ServiceTracker)的定义放回到标准中。在本例中我们创建了一个使用服务追踪器类的辞典服务客户端来监视辞典服务的动态可用性,我们以这种方法来提高客户端的�´健壮性¡。
这个新辞典客户端的功能基本上和示例四中的一样。我们的程序包使用其上下文环境创建一个用来为我们追踪辞典服务动态可用性的服务追踪器实例。我们的客户端使用服务追踪器返回根据OSGi标准中定义的排序算法选出的辞典服务。我们程序包的源代码在如下的Activator.java文件中:
/*
- Apache Felix OSGi 教程。 **/
package tutorial.example5;
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.util.tracker.ServiceTracker;
import tutorial.example2.service.DictionaryService;
/**
-
此类实现了一个使用辞典服务,以检查一个单词在辞典中是否存在
-
的方法检查其是否拼写正确的程序包。
-
此程序包比示例三中的程序包更加复杂因为其会监控辞典服务
-
的动态可用性。换句话说,如果程序包正在使用的服务消失了,它
-
便不会再去使用,或者在其需要一个服务时此服务加入进来,它
-
就会自动开始使用此服务。像先前的例子一样,程序包使用其找到
-
的第一个服务,而且使用默认方法start()从标准输入读取单词。
-
你可以以输入一个空行的方法停止单词检查,但如果想要再次开始
-
单词检查你可以停掉然后重新启动此软件包。 **/ public class Activator implements BundleActivator { // 软件包运行时的上下文环境。 private BundleContext m_context = null; // 服务追踪器实例。 private ServiceTracker m_tracker = null;
/**
-
实现BundleActivator.start()方法。创建一个服务追踪器来监视词典服务
-
并且开始其´单词检查循环¡。此程序不会检查任何单词直到服务追踪器
-
找到一个辞典服务,任何发现到的辞典服务都会被客户端自动使用。
-
程序会从标准输入读取单词并且检查其在找到的辞典中是否存在。
-
(注意:在默认方法里执行这样冗长的业务流程不是一个好的做法,
-
这里只是教程需要)。
-
@param context 程序包在运行时在框架中所处的上下文环境。 **/ public void start(BundleContext context) throws Exception { m_context = context;
// 创建一个服务追踪器以监视辞典服务。 m_tracker = new ServiceTracker( m_context, m_context.createFilter( "(&(objectClass=" + DictionaryService.class.getName() + ")" + "(Language=*))"), null); m_tracker.open();
try { System.out.println("Enter a blank line to exit."); String word = ""; BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
// 永远循环。 while (true) { // 提示用户输入一个单词。 System.out.print("输入单词: "); word = in.readLine(); // 如果有辞典服务被选用则将其获取。 DictionaryService dictionary = (DictionaryService) m_tracker.getService(); // 如果用户输入了一个空行,则结束循环。 if (word.length() == 0) { break; } // 如果没有得到词典,则提示。 else if (dictionary == null) { System.out.println("没有可用的辞典。"); } // 否则打印出单词是否正确。 else if (dictionary.checkWord(word)) { System.out.println("正确。"); } else { System.out.println("不正确。"); } }
} catch (Exception ex) { } }
/**
- 实现BundleActivator.stop()。 因为框架会自动放回所有正在使用的服务,
- 所以在这里不做任何事情。
- @param context 程序包运行时在框架中所处的上下文环境。 **/ public void stop(BundleContext context) { } }
-
因为此客户端使用ServiceTracker工具类,它会自动监视辞典服务的动态可用性,同样,我们必须要创建包含程序包导引信息的manifest.mf文件:
Bundle-Name: Service Tracker-based dictionary client Bundle-Description: A dictionary client using the Service Tracker. Bundle-Vendor: Apache Felix Bundle-Version: 1.0.0 Bundle-Activator: tutorial.example5.Activator Import-Package: org.osgi.framework, org.osgi.util.tracker, tutorial.example2.service
我们通过Bundle-Activator属性指定程序包接口,并且通过Import-Package指明我们的程序报引入了OSGi框架核心包,服务追踪器包和辞典服务接口包。OSGi框架会自动处理导入包的细节问题。(提示:确信你的manifest文件的尾部以回车结束,否则最后一行会被忽略)
为了编译这个源文件,我们需要在classpath中加入felix.jar文件(可以在felix套件的bin目录下找到),我们用如下命令编译源文件:
javac -d c:\classes *.java
此命令会编译所有的源文件并且把生成的类文件输出到c:\classes目录中一个子目录下,这个子目录就是tutorial\example5,按照我们在源文件中制定的包名命名。为了让以上命令能够正常执行,目录c:\classes必须存在。编译后,我们必须创建一个JAR文件以包装生成的包目录,而且要将包含软件包导引信息的描述文件一并添加到JAR包中。我们使用如下命令创建这个JAR文件:
jar cfm example5.jar manifest.mf -C c:\classes tutorial\example5
此命令利用我们创建的描述文件创建了一个JAR包而且包含了在c:\classes目录下的tutorial\example4目录中所有的类文件。当此JAR文件成功创建后,我们便可以准备安装并且启动此程序包。
我们按照usage.html中描述的步骤启动Felix,当我们启动Felix后,程序会询问一个档案名,我们可以将我们所有的程序包置入一个名为 "tutorial"的档案中。启动Felix後,我们要确信教程中描述的所有程序包除了示例二中的英语辞典服务程序包外都是停止的。我们可以使用 Felix的 shell命令 ´ps¡获取所有程序包的列表,以及它们的状态和标记值。如果示例一中描述的程序包不是有效(activa)的,我们必须使用start命令和´ps¡命令打印出的那个标记值将其启动并且使用stop命令停掉所有其他在本教程中不需要的软件包。(注意: Felix使用一些程序包来提供命令行交互接口,所以不要把这些软件包停掉)现在我们可以安装并且启辞典服务程序包。假如我们的把我们的程序包创建在c: \tutorial。我们可以在Felix shell中使用如下方法将其安装并且启用:
start file:/c:/tutorial/example5.jar
上述命令可以在一个步骤里安装并启动这个软件包,同时也可以使用install和start两个命令分两步安装并启动此软件包。当我们启动软件包後,它会使用它会使用shell提示我们输入单词。这时如果想检查一个单词则将其输入如果想退出则可以直接输入一个空行。如果想要重新启动这个软件包,我们必须使用Felix shell中的ps命令获取此软件包的标识值,然後首先使用stop命令停掉这个软件包,然後使用start命令将其重新启动。想要测试这个辞典服务,可以输入辞典中的单词(例如´welcome¡、´to¡、´the¡、´OSGi¡、´tutorial¡),或者辞典中没有的单词。
因此客户端使用了服务追踪器类,当辞典服务突然消失的时候会显得更可靠。然后,当一个辞典服务加入时,如果它需要此服务的话会自动获取然后继续运行。在解释这些功能的时候有一点困难,因为我们在这里使用单线程的方法处理问题,但在多线程或者面向用户界面的程序中,´健壮性¡就显得十分重要。