编写 Java 类来管理 RPM 包内容
首次安装 Linux 系统非常简单。您可以在市场上找到物美价廉的 Linux 软件包,它们可以快速自行安装。您只需选择一些配置选项来描述您要安装的硬件类型即可。
随着时间的推移,您将向 Linux 系统添加一些新组件,而噩梦可能就此开始。一个 Linux 系统由数百个组件和动态库组成。为了保持系统的正常运行,您应该小心,因为安装新版本的组件可能会给您的系统带来不兼容性,随着时间的推移,系统会变得越来越不稳定。
用新版本替换现有组件乍一看似乎是一项微不足道的任务:您只需获取组件的新编译版本,通常在网络上以 .tgz 文件(tar + gzip 压缩)的形式提供,并将其安装到您的系统上。您刚刚升级的组件的某些动态库可能已被其他已安装的组件使用,并且可能与您刚刚安装的新版本不兼容。
如果有一个工具可以报告系统上安装的每个组件的依赖关系,那就太好了。这样的工具可以告诉您系统上安装的 Samba 版本(例如),或者在 binutils 2.9 运行之前,您无法在系统上安装 egcs-1.0.2-8。Linux 上已经存在这个工具——它被称为 RPM——并且存在于许多现有的 Linux 发行版中,包括 Red Hat、Caldera、SuSE 和 Linux Mandrake。
RPM 代表 Red Hat Package Manager(红帽软件包管理器),其创建者将其描述为“任何人都可以使用的开放式打包系统,可在 Red Hat Linux 以及其他 Linux 和 UNIX 系统上运行”(摘自 Red Hat 安装指南)。
在开始编程讨论之前,我将介绍 RPM 软件包管理器,并对其进行总体概述。如果您需要更多信息,请参阅“资源”,其中包含 400 多页关于 RPM 的历史、设计、用法和编程的有趣详细信息。
图 1 中的图表代表了 RPM 工具中涉及的不同组件。RPM 由三个主要部分组成
数据库
候选软件包
RPM 实用程序,用于修改数据库和软件包
RPM 数据库位于 Red Hat 发行版的 /var/lib/rpm 中,归 root 所有;它是当前安装在您系统上的所有软件包的镜像。RPM 实用程序接受各种命令,这些命令查询数据库以查找已安装的软件包,使用新的 RPM 软件包安装或更新系统,从系统中删除未使用的软件包,以及验证和检查已安装软件包的依赖关系。通常,当给定组件的新版本在网络上可用时,您有两种选择
查找包含源文件的 tar gzip 文件。在您的系统上编译源代码,然后继续安装二进制文件。给定的软件包通常提供 README、make 和 make install 过程来帮助您。
查找包含二进制文件的 tar、gzip 文件,这意味着其他人已经为您在与您同类型的计算机上编译了源代码。然后继续安装二进制文件。
假设您有兴趣安装 Samba 的 1.9.18 版本。首先,您应该在网络上查找 Samba 软件包的 RPM(而不是 tar、gzip 软件包)。获得它后,输入
rpm -uvh samba-1.9.18p8-50.1.i386.rpm
此命令将在您的系统上安装(或升级)Samba 的副本。它还将检查系统上是否存在此版本的 Samba 所需的所有依赖项。如果 rpm 命令完成且没有错误消息,则可以保证安装的软件包将在安装过程结束时准备好运行而不会出现问题。
此安装过程还将更新 RPM 数据库,该数据库跟踪系统上安装的所有软件包及其所有依赖项。
因此,如果在六个月后,您想找出系统上安装了哪个版本的 Samba,输入以下命令
rpm -q samba
会告诉您
samba-1.9.18p8-50.1如果您想从系统中删除软件包,RPM 实用程序将删除安装期间安装在系统上的文件。
我认为,如果您希望在多个 UNIX 和非 UNIX 系统上具有可移植性,并且易于在 Internet 环境中使用,那么只有两种可能性:Perl 或 Java。从技术的角度来看,没有理由偏爱其中一种。选择是个人决定。
我比 Perl 更有 Java 编程经验。经过漫长而艰难的思考过程,我决定从 Java 入手,理由是如果我以后需要向组件添加图形演示类,我可以使用 Java Swing 软件包(JDK1.1 或 JDK 1.2 随附)。
如果您查看 Red Hat 发行版的 /usr/lib 目录,您会找到 librpm.a 静态存档库。此库随附其相应的 C 语言原型:rpmlib.h、header.h 和 dbindex.h,位于 /usr/include/rpm 中。
如果您需要开发处理 RPM 资源的 C 实用程序,可以使用这些原型。E. C. Bailey 的书(请参阅“资源”)的第 21 章提供了有关如何执行此操作的详细信息。但是,由于我们希望提供独立的 Java 软件包,因此这些原型对我们没有意义。
正确的开始位置(在同一资源中)是附录 A:RPM 文件格式,它为我们提供了 RPM 文件格式。同一附录还为我们提供了以下明智的建议:“RPM 文件格式可能会更改。”
如果要操作 RPM 文件格式,强烈建议您使用 RPM 例程来访问软件包文件。为什么?“RPM 文件格式可能会更改”!
在我们的例子中,我们将假设查询现有 RPM 软件包没有直接危险,因为我们承诺永远不会在我们的 Java 软件包中修改其结构。
非常令人困惑。请确保让一双 技术 眼睛检查一下,以确保听起来没问题。Dave Wright 的更改已合并。-Ellen
图 2 代表了 UML 格式(统一建模语言)的 Java RPM 类设计结构。让我们更详细地解释一下。UML 类设计提供了对 RPM 软件包的清晰高级表示。
内容是关于软件包及其安装规则的有趣信息。内容本身(为了清晰起见,未在 UML 图片中表示)只是一个压缩存档。解压缩后,它是一个 SVR4 格式的 cpio 存档,带有 CRC 校验和(请参阅“资源”)。
我将 RPM 对象与其图形表示形式完全分离。图 2 中的类仅实现对 RPM 文件的操作;它们不提供任何图形表示。将添加另一个名为 RpmFilePanel 的类,以提供简单的 Swing 显示,该显示将以图形方式操作基本的 RpmFile 类,该类旨在实现 RPM 文件的行为。
第一个有趣的类是 RpmException 类。此类继承自基本的 Java Exception 类,并实现了一个不带参数的默认构造函数和一个带有 String 消息参数的构造函数。此类是 RpmFile Java 软件包呈现的唯一异常。我确信,在编写新的 Java 软件包时,您应该做的第一件事是为该软件包构建一个异常包装器。稍后,RpmFile 软件包的所有类都将在出现问题时抛出带有准确消息的 RpmException。从面向对象的设计角度来看,此技术提高了设计的稳健性,为您的软件包提供了与基本系统层的完全隔离。当然,您也可以在 C++ 中做同样的事情。唯一的问题是某些 C++ 编译器实现可能不支持异常,并且 C++ 代码的可移植性可能更难实现。
下一个公共 Java 类是 RpmFile 类本身。RpmFile 类提供的公共方法实现以下基本服务(构造函数提供了构建类实例的能力。它不带任何参数。)
set_rpmFileName (fileName) 方法:这需要一个 URL 文件名字符串作为其参数。此方法将 RpmFile 实例与表示要查看的有效 RPM 软件包的 URL 绑定。如果在绑定期间出现问题,则会抛出 RpmFileException。
Vector get_rpmReport() 方法:一旦 RPM 软件包已绑定到 RpmFile 实例,就可以调用此方法来获取软件包信息。此方法返回的信息使用一个 String 向量,其中包含 RPM 软件包标头结构中找到的所有信息。
RpmFile 逻辑基于以下两个内部类
_RPM_LEAD_:由 RpmFile 类内部实例化,以验证加载的 RPM URL 文件的 RPM 引导结构。
一旦 _RPM_LEAD_ 得到验证,RpmFile 类将实例化一个 _RPM_STRUCTURE_HEADER_ 类,该类用于检查 RPM 文件标头内容。标头内容由存储在内部数组中的多个 _RPM_INDEX_ENTRY_ 组成。此数组的每个元素代表一段标头信息,稍后将通过 get_rpmReport 方法提供。由于没有理由让这些类对 RpmFile 之外的普通人可见,因此它们已作为 RpmFile 类内部的内部 Java 类实现。图 3 中提供了更精确的 UML 图。我使用了 JVision 1.2 工具从 Java 源代码自动生成 UML 类图。JVision 是 Object Insight (http://www.object-insight.com/) 提供的一个非常有趣、易于使用的工具。此工具能够从 Java 源代码类自动生成 UML 图。虽然不是免费的,但与其他产品相比,许可价格是合理的。我已经使用它一年多了,它帮助我生成 Java 项目文档。该产品的 Linux Beta 版本(免费供非商业用途)可在 Object Insight 网站上获得。
现在,我们能够操作 RPM 软件包标头的基本类结构已就位,添加一个最小的 GUI 界面将是一个好主意。我们将使用 Java Swing 软件包构建这个非常简单的界面,该软件包随 JDK 1.1 或 JDK 1.2 提供。
这个非常简单的 GUI 界面由 RpmFilePanel.Java 类管理。此类继承了基本的 JPanel 图形组件,并使用 Java BorderLayout 将屏幕分为三个部分
URL 输入字段,用于以 URL 格式输入 RPM 输入文件位置
可滚动的 ListBox,用于显示 RPM 文件信息
按钮栏,其中包含一个“加载”按钮,用于继续加载 URL RPM 文件。现在让我们解释 GUI 界面 RpmFilePanel Java 类如何与 RpmFile 类交互。
RpmFilePanel.java 文件包含一个静态 main 方法,用于在 Java 应用程序中启动 Swing 框架。您可以使用 shell 中的 JDK Java 实用程序来启动它
java rpm.RpmFilePanel
警告:您应该已编译 Java 软件包并将其安装在可从您的 CLASSPATH 访问的位置。
您应该以 URL 形式提供有效的 RPM 软件包文件,并将其键入到 URL 字段中,如下所示。最后,按下“加载”按钮将
实例化一个新的 RpmFile 实例
使用 URL 字段的 RPM 调用 set_rpmFileName 方法
调用 get_rpmReport 方法并将其 String 向量结果显示到 Swing List 框中,如下所示
图 4 显示了查询 RPM 软件包后的屏幕布局。
当您需要构建提供的源代码包时,可以使用 JDK 1.1 版本或 JDK 1.2.2 版本。如果您使用 JDK1.1,则先决条件是从 Sun 网站下载 Swing 软件包。
使用 Java 分析 RPM 文件格式可能很有用,并且它为您提供了跨平台的可移植性,这可能有助于您在异构平台上显示 RPM 文件内容。这个基本工具可以很容易地得到增强,例如将 RPM 内容转换为其他格式或提取 RPM 软件包的其他部分。

Jean-Yves Mengant (jymengant@ifrance.com) 是 SEFAS Technologies 公司(位于法国巴黎)的首席架构师。他是一位拥有超过 20 年经验的专业程序员,精通多种操作系统(MVS、Linux)、语言(汇编程序、C、C++、Java 和 Perl)和软件主题(网络、Tp 监视器和 GUI 界面)。自 1995 年和内核 1.2 以来,他一直专业地使用 Linux 系统进行编程任务,自 1996 年和 JDK 1.0 以来,他一直使用 Java 语言。