欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

eclipse管理jar包_了解Eclipse的新包管理机制

程序员文章站 2024-02-02 22:59:40
...

测试团队升级到Eclipse V3.2之后不久,我们发现Eclipse在我们的测试案例中不再支持AutoStart标头。 Eclipse Foundation用LazyStart代替了AutoStart,这是OSGi R4.1规范中采用的惰性**策略。 此更改的不利之处在于,我们发现很难在LazyStart中触发自动物镜束。 传统自动化测试用例需要公开要由触发器包加载的资源。 由于更新所有旧式测试用例笨拙且耗时,因此我们决定采用其他方法。

一种可能性是Eclipse控制台,这是一种操纵捆绑软件生命周期管理的强大工具。 但是,Rational Functional Tester无法识别Eclipse控制台。 我们的解决方案是设计和实现GUI控制台。

自动化测试中的空白

Eclipse是用于开发应用程序的流行IDE,并且由于使用了胖客户端平台(RCP),Eclipse是一个运行时平台,可用于不断增长的应用程序列表,包括IBMNotes®Client,Sametime®和Expeditor。 (请参阅相关的主题 ,如果你是新的Eclipse和需求的背景可以在Eclipse的功能的信息。)在自动化测试用例实践中,测试者面对一个严重的问题,尝试利用自动化工具,如IBM Rational Functional Tester中,发展自动化基于Eclipse RCP的产品的测试用例。 (关于Rational Functional Tester的对象识别详细信息,请下载“ 使用IBM Rational Functional Tester捕获GUI对象 ”。)

IBM Rational Functional Tester无法识别Eclipse或基于Eclipse的产品的控制台。 当自动化测试人员尝试通过IBM Rational Functional Tester抓住Eclipse的控制台对象时,它无法识别该控制台。 因此,自动化测试人员无法继续执行后续任务。 图1是IBM Rational Functional Tester无法识别Eclipse控制台的屏幕截图。 Rational Functional Tester识别控制台的预期动作是在图1中围绕控制台的红色矩形。当Rational Functional Tester识别Eclipse中的其他小部件(例如任务窗口,菜单栏,和组合列表。

图1. Rational Functional Tester无法识别Eclipse控制台
eclipse管理jar包_了解Eclipse的新包管理机制

因此,Rational Functional Tester无法识别Eclipse控制台是致命的,因为自动化工具需要控制台执行以下两项任务。

捆绑作业
出于明显的原因,我们需要检查和跟踪基于Eclipse RCP的产品中目标包的状态。 但是,在没有控制台帮助的情况下,自动化测试人员必须开发和部署新的手动测试。 测试人员必须将旧的自动化测试转换为手动测试用例。 测试方案必须在RCP应用程序中安装,卸载,启动,停止和定位捆绑软件。 这可以在控制台的支持下完成。 通常,使用场景会在控制台中调用这些命令,该控制台提供了一种检索回显结果的机制。
收集诊断信息
当Eclipse遇到错误时,它应该将异常和错误输出到控制台。 此类信息对于诊断问题的根本原因至关重要。 开发人员始终希望测试人员为每个软件问题报告提供此类信息,但是Rational Functional Tester无法在自动化测试期间收集它们。 这意味着测试人员需要手动重新运行测试以收集此信息。 对于长时间运行和压力测试而言,这几乎是不可能的。

为了弥补这一差距,我们提出了一种称为GUI控制台的解决方案。

需求识别

捆绑软件生命周期管理:AutoStart与LazyStart

在MANIFEST.MF标头中,可以将AutoStart和LazyStart视为同一bundle-manifest标头的同义词,但不赞成使用前者,而首选后者。 在修复Eclipse V3.1.2中的537个错误(使我们进入Eclipse Europa)期间,AutoStart陷入了困境。 今天,它是所有关于OSGi V3.2遵从性和使用LazyStart(请参阅相关主题 ,详细了解包如何对自己在MANIFEST.MF文件描述信息)。

在Eclipse V3.2中,LazyStart标头定义了一个束是否将在其类之前自动启动,或者是否由其他束访问资源。 通过将该值设置为true,我们可以懒惰地(即自动)**捆绑软件,这是有人第一次尝试加载类或资源时。

正如我们所描述的,尽管将所有旧的测试用例迁移到LazyStart是合乎逻辑的,但这样做将是一项巨大而笨拙的工作。 更新所有测试用例以支持AutoStart会将一种资源暴露给它们,并通过触发器捆绑包加载它们。 此外,启动捆绑包并不能满足我们自动化测试用例的所有要求。 捆绑状态管理(即“捆绑生命周期操纵”)涉及我们测试用例中的验证点。

捆绑软件生命周期管理:捆绑软件状态

一个包(包括我们的自动化测试用例中的包)一次只能处于以下六个状态之一。

已安装
成功安装捆绑软件后,捆绑软件可以进入INSTALLED状态。
解决
当捆绑包所需的Java类可用时,捆绑包可以进入RESOLVED状态。 换句话说,此状态表明框架已成功解决清单中描述的bundle的依赖关系。 RESOLVED状态来自INSTALLED或ACTIVE状态,并导致ACTIVE。
开始
当捆绑包启动时(当BundleActivator.start()方法被调用但尚未返回时),它可以进入STARTING状态。
活性
当捆绑包已启动并正在服务时,它可以进入活动状态。
停止
停止捆绑时(当调用BundleActivator.stop()方法但尚未返回时),捆绑可以进入STOPPING状态。
未安装
卸载捆绑软件后,捆绑软件可以进入UNINSTALLED状态。 它无法进入另一种状态。

Bundle接口定义了一个getState()方法来返回bundle的状态。

图2展示了捆绑软件生命周期中的所有状态,以及其过渡路径。

图2. OSGi捆绑软件状态
eclipse管理jar包_了解Eclipse的新包管理机制

检索清单标题

MANIFEST.MF中的标头是GUI控制台基础的另一部分。 Eclipse希望软件包开发人员在名为MANIFEST.MF的清单文件中提供有关软件包的描述性信息。 这是OSGi文件,用于定义清单标头,例如Export-Package和Bundle-Classpath描述。 表1列出了OSGi捆绑包中最有用的标头。

表1. OSGi捆绑包的标头
OSGi捆绑包头 描述
束**剂 指定用于启动和停止捆绑软件的类的名称。
捆绑类路径 指定包含类和资源的JAR文件或目录。 句点(。)是默认值,它指定捆绑软件JAR的根目录。
捆绑联系地址 包含供应商的联系地址。
捆绑版权 包含此捆绑软件的版权规范。
捆绑DocURL 指定一个URL,指向有关此捆绑软件的文档。
包本地化 指定包的本地化文件的位置,其默认值为OSGI-INF / l10n / bundle。
Bundle-ManifestVersion 指定捆绑软件遵循OSGi规范V3或OSGi规范V4的规则。
捆绑名称 指定包的可读名称,不带空格。
Bundle-SymbolicName 为该捆绑包指定唯一名称的必需标头。
捆绑销售商 包含捆绑销售商的可读名称。
捆绑版本 指定捆绑软件的版本,其默认值为0.0.0。
出口包装 指定从该捆绑包中导出的软件包。
片段主机 定义此片段的主机捆绑包。
进口包装 声明此捆绑软件的导入软件包。
需求捆绑 指定从另一个捆绑包导出的必需项。
导入服务 不推荐使用
出口服务 不推荐使用

要求摘要

根据以上需求分析,要求GUI控制台解决方案提供以下命令来支持针对我们的自动化测试用例的OSGi软件包管理。

表2. GUI控制台支持的OSGi命令
命令 描述
安装+捆绑URL 将具有给定URL的捆绑软件添加到当前平台中。
卸载+捆绑ID 从当前平台中删除指定的捆绑软件。
ss 列出当前平台中注册的所有捆绑包的简短状态。
开始+捆绑ID; 开始+捆绑名称 使用给定的包ID或符号名启动包。
止损+捆绑ID; 停止+捆绑名称 终止具有给定包ID或符号名的包。
标头 列出具有ID或符号名的捆绑包的清单标头。
活性 列出当前平台中的所有活动捆绑包。
更新 更新当前实例的捆绑软件。

设计与实施

在本节中,我们将说明为什么将BundleContext对象和bundle对象选择为我们的GUI控制台解决方案中的关键人物,并且我们将讨论OSGi中的bundle管理。

BundleContext

BundleContext是连接Eclipse框架和其中安装的捆绑软件的桥梁。 BundleContext对象代表OSGi平台内捆绑软件的执行上下文,并充当基础框架的代理。

启动捆绑包时,框架将创建一个BundleContext对象,并将其作为捆绑包的Bundle-Activator的start(BundleContext)方法的参数提供。 捆绑软件可以将此私有BundleContext对象用于:

  • 在OSGi环境中安装新的捆绑软件。
  • 询问OSGi环境中其他已安装的捆绑软件。
  • 获取持久存储区。
  • 检索注册服务的服务对象。
  • 在框架服务中注册服务。
  • 订阅或取消订阅框架广播的事件。

每个捆绑软件都有其自己的BundleContext对象,因此不应在捆绑软件之间传递它们。 为什么? BundleContext对象与包的安全性和资源分配方面有关。 当返回Bundle-Activator的stop(BundleContext)方法时,BundleContext对象停止服务。

BundleContext最有用的一点是,它定义了一些方法来检索有关OSGi服务平台中安装的捆绑软件的信息:

getBundle()
返回与BundleContext对象关联的单个bundle对象。
getBundles()
返回框架中当前安装的捆绑软件数组。
getBundle(long)
返回由唯一标识符指定的包对象;如果找不到匹配的包,则返回null。

因为没有捆绑软件访问限制,所以任何捆绑软件都可以枚举已安装捆绑软件的集合。 这使我们能够执行和操纵自动化测试用例的捆绑软件生命周期管理操作和捆绑软件信息检索操作。 GUI控制台将使用清单1中的代码检索所有活动包信息。它的功能与Eclipse控制台的active命令相同。

清单1. Active命令实现代码
public static void doActive() throws Exception {
    b = bContext.getBundles();
    for (int i = 0; i > b.length; i++) {
        if (b[i].getState() == b[i].ACTIVE) {
	result = result + b[i].getLocation()+" " + "["+b[i].getBundleId() +"]"
                 +System.getProperty ("line.separator");
		    } 
		}
		result=result+p+" active bundle(s).";
	}

对于广受欢迎的ss命令,只有在我们接受具有各自状态的所有捆绑软件(包括INSTALLED,RESOLVED和ACTIVE)的GUI控制台时,GUI控制台才能基于上述代码实现它。 有关详细信息,请参见示例代码

捆绑对象

要使用基于Eclipse的产品在OSGi平台中管理包的生命周期,我们必须为目标包使用一个关联的包对象。 BundleContext接口提供以下安装捆绑软件的方法。

installBundle(String)
从指定的位置字符串(URL)安装捆绑软件。
installBundle(String,InputStream)
从指定的InputStream对象安装捆绑软件。

成功安装捆绑软件后,将为其生成捆绑软件对象,并且必须使用该对象执行生命周期管理的所有操作,例如启动,停止和卸载。

如清单2所示,我们可以安装包含其位置字符串的捆绑软件。 如果捆绑软件已成功安装在平台中,它将返回捆绑软件的符号名称。

清单2. Active命令实现
public static String doInstall(String location) throws Exception{
                ...
		Bundle iBundle = bContext.installBundle(location);
		if(iBundle!=null){
			iBundle.update();
			return iBundle.getSymbolicName();
		}
		return null;
	}

开始捆绑

bundle接口定义了start()方法以启动捆绑包,并将捆绑包从RESOLVED状态转换为ACTIVE状态。 前提条件是该捆绑包必须已成功解析; 否则,将抛出BundleException。

要执行包的start()方法,我们需要通过包清单文件中的Bundle-Activator标头将Bundle-Activator的类名通知OSGi环境。 OSGi环境将实例化此类的新对象,并将其强制转换为Bundle-Activator实例。 然后它将调用BundleActivator.start()方法启动捆绑包。

作为Bundle-Activator,bundle中的类必须实现Bundle-Activator接口,并将其声明为public和public默认构造函数。 但是,可以选择在每个包中提供Bundle-Activator。 例如,导出少量软件包的库捆绑包不需要定义Bundle-Activator。

当提供捆绑软件ID或符号名称时,我们的GUI控制台应用程序将调用以下代码来启动捆绑软件。

清单3. Start命令的实现
public static void doStart(int bID) throws Exception {
    if(bContext.getBundle(bID)!=null&&bContext.getBundle(bID).state==
    bContext.getBundle(bID).RESOLVED){
	bContext.getBundle(bID).start();
    }
}
public static void doStart(String s,String matchS) throws Exception {
    b = bContext.getBundles();
    ...
    for (int i = 0; i < b.length; i++) {
	if (b[i].getSymbolicName().indexOf(s) >-1 && (b[i].getState() == 
        b[i].RESOLVED) {
	    boolean isFragment=false;
	    Enumeration eKey = b[i].getHeaders().keys();
	    Dictionary dValue = b[i].getHeaders();
	    Enumeration eValue = dValue.elements();
	    while (eKey.hasMoreElements() && eValue.hasMoreElements()) {
		String sKey = eKey.nextElement().toString();
		if (sKey.equalsIgnoreCase("Fragment-Host")) {
		    isFragment=true;
		 }
	    }
	   if (isFragment==false){
		b[i].start();
	   }
     }				    
}

停止捆绑

bundle接口定义stop()方法来停止捆绑包,从而导致RESOLVED状态。 与停止包相关联的所有线程应立即停止。

卸载捆绑

bundle接口提供了uninstall()方法,用于从框架中卸载bundle。 该框架将通知其他捆绑包目标捆绑包已被卸载,删除与捆绑包相关的所有资源,并将目标捆绑包的状态设置为UNINSTALLED。

新安装的捆绑包不得使用已卸载捆绑包的软件包。 但是,如果卸载的软件包曾经导出过其他软件包使用的任何软件包,则框架将继续使这些软件包可用,直到重新启动框架或调用org.osgi.service.packageadmin.PackageAdmin.refreshPackages()方法为止。

下面的代码演示了GUI控制台如何从平台上卸载提供了包ID或符号名的包。

清单4. Uninstall命令实现
public static void doUninstall(String s, String matchS) throws Exception{
    b = bContext.getBundles();
    ...
    if (b[i].getSymbolicName().indexOf(s) >-1) {
	....
	b[i].uninstall();
    }
    ...
}
public static void doUninstall(int bID) throws Exception{	
    if (bContext.getBundle(bID)!=null){
	bContext.getBundle(bID).uninstall();
    }
}

检索清单标题

bundle接口提供了两种方法来返回清单头信息:

getHeaders()
返回包含捆绑包的清单标头和值(键值对)的字典对象。
getHeaders(String)
返回包含捆绑包的清单标头和值(键值对)的字典对象。

即使捆绑包进入UNINSTALLED状态, getHeaders方法也可以继续提供清单标头信息。

清单5.标Headers命令实现
Enumeration eKey = b[i].getHeaders().keys();
Dictionary dValue = b[i].getHeaders();
Enumeration eValue = dValue.elements();
while (eKey.hasMoreElements() && eValue.hasMoreElements()) {
    String sKey = eKey.nextElement().toString();
    String sValue = eValue.nextElement().toString();
    headers.append(sKey+" = ");
    headers.append(sValue+"\n");
}

执行

我们使用基于Eclipse的产品IBM Expeditor执行GUI控制台测试方案(请参阅参考资料 )。 要求我们在验证方案之前将GUI控制台安装到Expeditor或任何其他基于Eclipse的产品中。 之后,如图3所示,在执行过程中,我们使用一个名为PascalTriangle的示例包作为操作包。 通过将其JAR文件导出到文件系统中,我们将在GUI控制台上探索包管理操作,包括安装,启动,停止,卸载和其他操作。

GUI控制台的优点之一是在命令解释和执行期间将自动支持捆绑软件的符号名称和捆绑软件ID。 安装格式化为导出的JAR文件的包时,将以编程方式检索符号名称和包ID。 此外,为了为自动化测试执行提供最大程度的灵活性,您可以使用简单的正则表达式技术(包括start withcontainsperfect match搜索符号名称。

图3.操纵的捆绑包:Pascal捆绑包JAR文件已导出以进行测试
eclipse管理jar包_了解Eclipse的新包管理机制

为了演示支持OSGi的install命令的功能,我们将把操纵后的软件包导入到Expeditor或任何其他已经装有GUI控制台应用程序的基于Eclipse的产品中。 在GUI控制台应用程序中,按Browse(浏览) ,导航到PascalTriangle捆绑包JAR文件在文件系统中的位置,然后按OK 在文本字段中验证目标捆绑包的位置地址后,请按Install 如果您的PascalTriangle捆绑包可以通过GUI控制台和OSGi平台成功加载并解析,您将看到指定的捆绑包ID。

图4. Install命令方案
eclipse管理jar包_了解Eclipse的新包管理机制

如下所示,使用ss命令(按ss按钮)检查捆绑包的状态是否已解决。

图5. ss命令场景
eclipse管理jar包_了解Eclipse的新包管理机制

要启动捆绑软件,请在安装目标捆绑软件后按Start(开始) ,并通过文本字段自动检索其符号名称。 可以如下所示验证启动PascalTriangle包的执行结果。

图6. Start命令场景
eclipse管理jar包_了解Eclipse的新包管理机制

要在捆绑软件的清单文件中查看标题的详细信息,请按标题按钮。 因此,您可以查看目标捆绑包中的所有可用标头及其值。 图7演示了PascalTriangle包的headers命令。

图7.标Headers命令场景
eclipse管理jar包_了解Eclipse的新包管理机制

有时您需要列出平台上所有活动状态的捆绑包。 有关概述,请按** 有关详细信息,请参见图8。

图8. Active命令场景
eclipse管理jar包_了解Eclipse的新包管理机制

如下所示,我们发现GUI控制台捆绑包和PascalTriangle捆绑包在显示的末尾列出,并提供了其捆绑包ID。

图9. Active命令场景
eclipse管理jar包_了解Eclipse的新包管理机制

图10还演示了将目标包的JAR文件替换为更新后的Update命令时的Update命令。 我们可以在更新后找到打印的更新PascalTriangle。

图10. Update命令方案
eclipse管理jar包_了解Eclipse的新包管理机制

卸载软件包的操作如下所示。 通过ss命令验证结果,以按其符号名称搜索PascalTriangle包。 如我们所见,在卸载后,OSGi平台中不再存在PascalTriangle软件包。

图11. Uninstall命令场景
eclipse管理jar包_了解Eclipse的新包管理机制

摘要

IBM Rational Functional Tester无法识别Eclipse控制台。 从V3.2开始,Eclipse在旧式测试用例中不再支持Eclipse-AutoStart标头。 为了缩小差距,我们展示了一种称为GUI控制台的解决方案,该解决方案可与新的Eclipse-LazyStart一起使用。


翻译自: https://www.ibm.com/developerworks/opensource/library/os-eclipse-bundlemgmt/index.html