过滤

Orekit为数据提供了自动过滤功能。当使用默认配置通过DataProvidersManager实例加载数据时,此功能会自动激活,并且可以用于显式加载应用程序数据。

所有过滤器都实现了DataFilter接口,并可以注册到FiltersManager实例中。在默认配置中,有三个过滤器注册到DataProvidersManager中包含的FiltersManager中:

在加载时,将应用可以应用于一组数据的所有过滤器。例如,如果文件既加密又压缩(以任意顺序),并且存在用于解压缩和解密的过滤器,则在将数据提取到DataProvider之前,这两个过滤器将按正确的顺序应用于数据,并将其提供给DataLoader(或由用户在显式加载应用程序数据时设置的解析器)。

以下类图显示了此功能涉及的主要类和接口。

数据过滤类图

过滤器堆栈

过滤原理基于DataSource实例的堆栈,底部是一个实例(在使用DataProvidersManager时由DataProvider创建,或在显式加载数据时手动创建)。堆栈底部的实例将直接从存储中读取字节或字符。在堆栈中向上,可以找到由FiltersManager.applyRelevantFilters方法根据需要添加的实例,每个实例从底层堆栈元素读取数据并向上一个元素提供过滤后的数据。

DataProvidersManager的情况下,如果DataSource的名称部分与DataLoader实例期望的名称匹配,则堆栈顶部的数据流将被打开。这是懒加载发生的地方,通常会导致所有中间字节或字符流也被打开。然后将打开的流传递给DataLoader进行解析。另一方面,如果DataSource的名称部分与DataLoader实例期望的名称不匹配,则既不会打开数据流,也会丢弃整个堆栈,并考虑从DataProvider中过滤和加载下一个资源/文件。

在显式加载的情况下,应用程序可以自行决定打开或丢弃顶层DataSource,或根据源名称选择适当的解析器,而无需担心像‘.gz’这样的扩展名,因为这些扩展名已经由较低级别的过滤器处理过了。

默认配置示例

一个示例将更清楚地解释这个方法。考虑一个配置为查找包含文件 tai-utc.datMSAFE/may2019f10_prd.txt.gz 的目录树的 DirectoryCrawler,考虑其中一个默认过滤器:GzipFilter,它可以解压带有 .gz 扩展名的文件(默认过滤器还包括 UnixCompressFilterHatanakaCompressFilter,为了清晰起见,它们被省略),以及考虑实现了 DataLoader 并可以加载文件名遵循 mmmyyyyf10_prd.txt 模式的 MarshallSolarActivityFutureEstimation

数据过滤序列图

tai-utc.dat 文件被 DirectoryCrawler 考虑时,会为其创建一个 DataSource。然后检查过滤器(图中只显示了一个过滤器),它们都拒绝对文件进行操作,因此它们都返回与原始文件创建的相同的 DataSource。在过滤器循环结束时,检查名称(仍为 tai-utc.dat)是否与数据加载器期望的模式匹配。由于不匹配,只由一个 DataSource 组成的堆栈被丢弃。在所有检查过程中,文件根本没有被打开,只有其名称被考虑。

然后,DirectoryCrawler 考虑下一个目录,在该目录中考虑下一个文件,即 may2019f10_prd.txt.gz。为其创建一个新的 DataSource 并检查过滤器。由于扩展名是 .gzGzipFilter 过滤器认为它可以对文件进行操作,并创建并返回一个新的 DataSource,其名称设置为 may2019f10_prd.txt(已删除 .gz 扩展名),并且懒加载流打开器设置为在原始文件字节流和提供的未压缩字节流之间插入一个解压算法。重新开始循环,但没有其他过滤器适用,因此最终堆栈包含两个 DataSource,底部一个从存储中读取并提供 gzip 压缩数据,顶部一个读取 gzip 压缩数据,解压并提供未压缩数据。由于顶部实例的名称与 MSAFE 数据的预期模式匹配,MarshallSolarActivityFutureEstimation 将能够加载它。在此阶段,DirectoryCrawler 调用打开堆栈顶层的字节流的方法。然后,该方法要求底层的 DataSource 打开其流(即原始文件数据),将该数据提供给 gzip 解压算法,并将输出的未压缩数据作为新打开的字节流。然后,数据加载器解析数据,而不知道它是即时解压缩的。

显式加载示例

当显式加载数据时,应用程序负责设置FiltersManager并调用它。以下示例显示了如何在图形界面中从用户选择的文件中加载CCSDS轨道星历消息,其中某些文件可能已使用gzip或Unix compress进行压缩,并且可能已在磁盘上加密,因为它们包含敏感信息(它们可以是压缩和加密的,任意顺序):

// 设置过滤器管理器,如果需要,可以在应用程序启动时仅执行一次
FiltersManager manager = new FiltersManager();
filtersManager.addFilter(new GzipFilter());
filtersManager.addFilter(new UnixCompressFilter());
filtersManager.addFilter(new MyOwnDecipheringFilter(secretKey));

// 设置CCSDS文件解析器的构建器
ParserBuilder parserBuilder = new ParserBuilder(dataContext);

// 解析文件
for (final File file : userInterface.getFilesToProcess()) {

    // 设置原始数据源,可以是压缩和/或加密的
    DataSource rawSource = new DataSource(file.getName(), () -> new FileInputStream(file));

    // 应用相关的过滤器
    DataSource filteredSource = manager.applyRelevantFilters(rawSource);

    // 解析文件,现在已知为未压缩和解密的
    OEM oem = parserBuidler.buildOemParser().parse(filteredSource);

    // 处理星历
    ...

}