本系列将会循序渐进地介绍一组标准技术,这些技术使得集成来自不同来源的数据变得非常容易。第一篇文章 “ 使用 RDF 创建数据网络 ” 讨论了如何使用面向资源的数据模型来简化信息共享。使用标准标识符和图表来表示实体和它们的关系,让信息能够流动和累积,无论它们来自何处。第二篇文章 “使用 SPARQL 查询 RDF” 添加了标准查询机制来询问共享信息的问题。第三篇文章 “Linked Data” 演示了使用这些技术来建立数百个来源的大规模集成。现在您已经看到了 RDF、SPARQL 和 Linked Data 能带来的可能性,本期和下一期文章将介绍这些技术在软件生命周期管理领域的应用。但是首先,我将快速介绍一些有助于激起我撰写有关这些技术的文章的经验。
作为软件开发人员,我始终知道优秀的工具对我的日常任务的价值:变更管理 (CM) 系统、构建工具、测试工具,以及最新的持续集成和交付工具。但在我早期的职业生涯中,我对针对软件生产的业务方面而设计的工具不屑一顾。需求管理、测试计划管理、项目管理和类似工具似乎是毫无价值的昂贵玩具。它们似乎脱离了现实 — 总是追求时尚,从不反映项目的任何大体状态。(开发人员的工作就是寻找真相。)而且无法将一个工具中的信息与另一个工具中的信息相联系。
本系列将介绍、探讨和应用全球标准,解决开发人员、架构师和数据管理员每天所面临的大规模数据集成难题。本系列介绍的一些跨平台的、独立于语言和应用程序的技术,支持在数据库、文档、电子表格、服务 API 中进行信息集成。您将了解的数据模型和工具可以让您的工作变得更轻松,并对您的组织产生实质性的影响。
后来,一位前上司(Number Six Software 公司后来的 Brian Lyons)将整个 Rational Software 工具套件整合在一起,这让我大开眼界。通过使用 Rational Rose 作为中心,他将 Requisite Pro、Rose、ClearCase 和当时 Rational 的所有测试工具连接在一起。他凭借对工具套件的精通而释放的能力对我有很大的启发。我看到他将需求连接到用例,将实现连接到代码、测试、测试结果以及它们之间的所有代码更改。例如,Lyons 在 Rose 元素上使用颜色编码来指示测试范围和状态。借助这个集成的工具套件,您可以将业务需求、编写需求的人、代码和生成代码人组合在一起。
如果发生软件故障,您知道这些故障位于何处,谁导致产生了这些,以及它们与哪些需求又关联。我逐渐清楚地认识到软件故障是一个组织问题,而不一定是个人的错误。如果没有明确地指定需求,可以想象,开发人员在设计和构建他们认为需要的功能时会感到困惑。需求、代码或二者的质量可能是导致故障的原因。能够确定问题的来源非常令人兴奋。在过去,这就是敏捷开发的前身,所以跨业务和技术边界来实现度量和集成的想法既令人兴奋,又让人感到新颖。
惟一的问题是,您需要拥有一个通过自定义脚本语言相互链接起来的大型、复杂的工具套件的专家级知识。在参与创立自己的公司之前,Lyons 曾在 Rational 工作;他精通所有 Rational 产品,这是大部分人都做不到的。我当时感觉看到了未来的大体景象,但事实并非如此。
几年后,我和 IBM Rational 当时的 CTO Martin Nally 联合举办了一场专题会议。我从他那里了解到,IBM Rational 正在尝试再次实现工具集成 — 通过 REST 接口和 XML 结构。那时,我已成为 Linked Data 和语义 Web 集成技术的忠实拥护者,我对自定义 XML 文档格式的使用感到很遗憾。但令人印象深刻的是,至少在理论上,任何工具都可以彼此通信,只要工具制造者就所交换内容的格式达成一致。
IBM Rational 的计划称为开放式生命周期协作服务 (OSLC)。在我最终调查了解 OSLC 时,我惊喜地发现,它基于使用 RDF、HTTP、REST 架构原理和 Linked Data 的开放标准。该小组陆续招募了几十位参与者。在生成和使用基于标准的工具数据的这些纵向部分的 组织 中,您会找到金融机构、蓝筹技术公司、国防公司、开源项目、政府组织和对开发人员友好的创业公司。
“ 将工具生成者汇集起来参加一个复杂的、需达成共识的规范计划,这似乎是一件不可能做到的事。一种轻量型、灵活、可扩展、基于标准的方法非常有意义。 ”
这个小组最终明确认识到,在所有参与者之间(跨应用程序生命周期管理 (ALM) 和产品生命周期管理 (PLM) 工具套件)达成了一致是不可能实现的。向组织销售完整的工具套件也是如此。普通的软件开发团队已在投身开发一种类似 Git 或 Subversion 的 CM 系统,集成众多其他的商业、开源或自定义工具。花时间将所有这些不同的工具生成者汇集起来,实施一个复杂、需要达成共识的规范计划,也是不可能的。最终,一种轻量型、灵活、可扩展、基于标准的方法变得很有意义。这些是本系列已向您介绍的技术。它们在网络上工作,它们 像 一个网络一样工作。本文和下一篇文章将探讨它们在某个具体问题上的应用。
回页首
OSLC 社区生成了一系列工具集成规范。该计划正处于 3.0 阶段,已被 OASIS 标准小组选中来承担其工作。OSLC 的目的不是通过过多地指定工具应如何进行通信来过度扩大其影响力,而是采用一种 “刚好足够的” 集成方法。该工作基于 Linked Data 和 HTTP 等标准以及 REST 架构风格等实践。具体的工作组解决各个子领域的问题,比如需求管理、变更管理、配置管理、测试等,但他们都基于一组核心的概念和风格,以保持可互操作。
该项目的目标是构建一些 功能 和 词汇表 ,使系统具有以下特征:
OSLC 组建了各个技术委员会 (TC) 来解决术语和类型的规范,为特定领域创建词汇表。举例而言,每个 TC 可专注于质量管理工具的一个独特方面,但他们可以在跨领域集成中重用术语,只要这么做有意义。这延续了跨工具和场景的最低限度但足够(“刚好足够”)的集成的方法。
解决它的一些早期的词汇表和表达 ALM 系统工件的方式后,OSLC 社区认识到,实际运行的软件有必要帮助推广这些创意。如果它指定一种架构集成过多的功能,对实现的影响可能赶跑工具生产者。如果它为架构指定的功能不足,各个工具可能迥然不同,难以轻松且一致地共享信息。
OSLC 计划是一个过渡时期。从 2.0 版到 3.0 版的升级涉及到改变项目的主页和范围,采用 LDP 作为架构的基础。许多主要的参与者都已发生改变。从教程和文档中,可能不太明白哪些数据是最新的,哪些是早期的。OASIS 是一个大型、复杂的组织,需要成为其成员才能访问许多交互功能。幸运的是,我们开始看到这些网页开始朝一种清醒的方向发展。您可以在 工作组 页面上找到最新的活动。
不会单独解决特定领域元素(比如需求或变更)的问题,OSLC 认为一个管理各种数据类型和它们彼此之间的关系的可重用平台会很有用。与此同时,万维网协会 (W3C) 开始收到反馈,表明成员想要一个管理链接数据的读/写平台。OSLC 决定加入其他这些小组,通过提供参考实现来成为关键的贡献者,这个实现形成了有关最终的 Linked Data Platform (LDP) 规范的讨论的基础。
OASIS OSLC 旗下有 4 个主要的 TC:
在最后一篇文章中深入剖析一个正常工作的 OSLC 系统之前,我将帮助您了解希望构建的工具所借助的基础架构。
回页首
“ LDP 基于 REST、网络和 Linked Data 的原则,但提供了更多结构来协调兼容的容器之间的行为。 ”
在理论上,我们想要引用的资源可由任何理解 HTTP 的容器承载。网络的松散耦合的主要优势之一是,客户端不需要对服务器的实现有任何了解。对于 OSLC 等希望建立一个可互操作工具社区的社区,需要一个围绕 Linked Data 资源的管理的稍微详细一些的行为规范。这正是 Linked Data Platform (LDP) 发挥其效用的地方。LDP 基于 REST、网络和 Linked Data 的原则,但提供了更多结构来协调兼容的容器之间的行为。如果工具供应商一致地理解并支持这些标准,生态系统才更有可能协同工作。只要支持这种面向资源的行为,实际实现细节仍然毫不相干。
Linked Data Platform 主要负责管理 Linked Data Platform 资源 (LDPR) 的状态。这些是可存储在 Linked Data Platform 容器 (LDPC) 中的任意资源。容器不同于 Web 服务器或数据库。您可在一个 LDP 实例中托管多个容器,将它们视为在其中存储资源的任意的逻辑容器。常见的示例包括一个用户的联系人列表,一个项目和它的相关缺陷,或者一个团队或它的成员。
为了简便起见,本教程的示例完全忽略了安全因素。LDPjs 不会对 LDPC 和其中存储的 LDPR 使用验证或授权保护。您在生产中使用的任何 LDP 实现都应使用一种验证和授权保护模型,比如 OAuth 2 。
客户端可与 LDPC 交互,通过 HTTP 和它的合适的方法来创建、检索、更新或删除 LDPR。LDP 的一个重要部分是资源发现。客户端了解一个容器中有哪些资源和它们彼此有何关系。LDP 有一个与一些词汇表术语有关联的命名空间 ( http://www.w3.org/ns/ldp#
),这些术语可跨这些概念的任何应用来进行重用。当我在示例中使用 ldp:
前缀时,这就是我引用的命名空间。
安装 LDP 的实现,以便您可以使用它。您有 多种选择 。我选择了 LDPjs ,这是一个容易使用、基于 Node 的版本。(参见参考资料,获取一个可试用的基于 Java 的实现的链接。)如果尚未安装 git 、 Node.js 和 Mongo ,请先安装它们。启动 Mongo,然后抓取 LDPjs 代码:
> git clone https://github.com/spadgett/LDPjs.git Cloning into 'LDPjs'... remote: Counting objects: 495, done. remote: Total 495 (delta 0), reused 0 (delta 0), pack-reused 495 Receiving objects: 100% (495/495), 256.19 KiB | 158.00 KiB/s, done. Resolving deltas: 100% (293/293), done. Checking connectivity... done.
现在,启动服务器:
> npm install ... npm output > node server.js configuration: { listenHost: 'localhost', listenPort: 3000, scheme: 'http', host: 'localhost', port: 3000, context: '/r/', appBase: 'http://localhost:3000', ldpBase: 'http://localhost:3000/r/', mongoURL: 'mongodb://localhost:27017/ldp' } App started on port 3000 Connected to MongoDB at: mongodb://localhost:27017/ldp
此刻,可以看到基础容器(由 config.json 文件定义)是 http://localhost:3000/r/
。LDPC 使用一个 HTTP 客户端(在本例中为 httpie )来揭示它的基本信息:
> http get http://localhost:3000/r/ HTTP/1.1 200 OK Accept-Post: text/turtle,application/ld+json,application/json Allow: GET,HEAD,DELETE,OPTIONS,POST Connection: keep-alive Content-Type: text/turtle Date: Sat, 13 Jun 2015 21:50:52 GMT ETag: W/"eb95ad12674f4327408681c918a91f51" Link: <http://www.w3.org/ns/ldp#Resource>; rel="type", <http://localhost:3000/constraints.html>; rel="http://www.w3.org/ns/ldp#constrainedBy", <http://www.w3.org/ns/ldp#BasicContainer>; rel="type" Transfer-Encoding: chunked Vary: Accept X-Powered-By: Express <http://localhost:3000/r/> a <http://www.w3.org/ns/ldp#Resource>, <http://www.w3.org/ns/ldp#RDFSource>, <http://www.w3.org/ns/ldp#Container>, <http://www.w3.org/ns/ldp#BasicContainer>; <http://purl.org/dc/terms/title> "LDP.js root container".
可以看到容器标识符只是另一种资源。您可像其他任何基于 HTTP 的资源一样与它交互。这是一些有关容器信息的重要观察结果:
根据 LDP 规范的定义,可以通过 POST
,以 Turtle ( text/turtle
)、JSON-LD ( application/ld+json
) 或 JSON ( application/json
) 的形式向 LDPC 添加新资源。
Accept-Post: text/turtle,application/ld+json,application/json Allow: GET,HEAD,DELETE,OPTIONS,POST
Turtle 是语义 Web 爱好者中一种流行的 RDF 序列化方式,但非语义 Web 框架很难使用它。 JSON-LD 是两个社区中一种越来越流行的格式,因为它能够将 RDF 序列化为一种适合基于 JavaScript 的框架的格式。
您还可以向容器本身发出其他 HTTP 方法。另一种需求是支持 OPTIONS
方法,以便客户端可确定它们能够对资源做什么。
您会看到,在默认情况下,LDPC 返回资源的 Turtle 表示。LDP 规范还要求支持 ETag,让客户端能够在 ETag 更改时检测到此更改:
Content-Type: text/turtle Date: Sat, 13 Jun 2015 21:50:52 GMT ETag: W/"eb95ad12674f4327408681c918a91f51"
尽管 Turtle 是默认的表示,但 LDPC 还应该支持内容协商。在本例中,您看到了对一种 JSON-LD 表示的成功请求:
> http get http://localhost:3000/r/ Accept=application/ld+json HTTP/1.1 200 OK Accept-Post: text/turtle,application/ld+json,application/json Allow: GET,HEAD,DELETE,OPTIONS,POST Connection: keep-alive Content-Type: application/ld+json ... { "@context": { "dcterms": "http://purl.org/dc/terms/", "foaf": "http://xmlns.com/foaf/0.1/", "ldp": "http://www.w3.org/ns/ldp#" }, "@id": "http://localhost:3000/r/", "@type": [ "ldp:Resource", "ldp:RDFSource", "ldp:Container", "ldp:BasicContainer" ], "dcterms:title": "LDP.js root container" }
响应标头中是几个符合 RFC 5988 的链接。两个链接有一种 type
类型的 rel
关系,表示容器是一个 LDP Resource
和一个 LDP BasicContainer
的实例。这很有用。您可以检索容器的描述,因为它是一种资源,而且您可以向它添加内容,因为它是一个容器。有多种不同的容器类型,但 BasicContainer
支持简单的交互和包含关系。尽管 type
是一种与 RDF 本身的重要关系,但也可以通过链接响应来表达其他特定于领域的关系。在本例中,还有一种特定于 LDP 的关系 constrainedBy
。此链接指向一个文档,您可以自由地解析该文档来查找何种约束适用于这个特定的 LDPC 和 LDP 实现:
Link: <http://www.w3.org/ns/ldp#Resource>; rel="type", <http://localhost:3000/constraints.html>; rel="http://www.w3.org/ns/ldp#constrainedBy", <http://www.w3.org/ns/ldp#BasicContainer>; rel="type"
有关 Vary
响应标头的简单说明:
Vary: Accept
因为服务器允许客户端使用内容协商来请求相同资源的不同格式,所以可以向中间处理器传播此事实来避免缓存问题,这非常重要。在这里,服务器宣布它的响应基于 Accept
标头而有所不同。这是一个容易忘记的步骤,如果忽略它,则有可能导致令人烦恼的调试会话。
最后,容器资源本身的一种表示既可视为 Turtle,也可视为 JSON-LD:
<http://localhost:3000/r/> a <http://www.w3.org/ns/ldp#Resource>, <http://www.w3.org/ns/ldp#RDFSource>, <http://www.w3.org/ns/ldp#Container>, <http://www.w3.org/ns/ldp#BasicContainer>; <http://purl.org/dc/terms/title> "LDP.js root container" .
这里复制了响应标头中传播的一些内容。这看起来可能比较浪费,但 RFC 5988 标头的部分价值在于,它们为不知道如何解析返回的表示的客户端提供了有用的信息。除了容器的标题之外,您还会看到它可被当作两种其他的类型。对容器本身的描述取决于具体实现和它的设置方式。大部分 LDPC 都使用了 LDP 术语,但可以使用的术语并不仅限于这些。
空容器不是很有趣。您已了解到,您可以向容器 POST
新资源,但为了增添乐趣,可以考虑使用 LDPjs 服务器也支持的 HTML 界面。该界面被传播,并在服务器启动后存在于 http://localhost:3000 上,可在 图 1 中看到。用户界面包含容器内容的漂亮的可视表示,目前容器是空的。这是标为 /r/ 的小文件夹所表示的内容。
图 1. LDPjs 实现的 HTML 界面
如果选择容器 URL 上方的 POST 链接,UI 会通过切换来显示 Turtle 中表示的一个示例错误报告,如 图 2 中所示。首先要注意的是,描述的内容没有标识出来。它是 Turtle 中一个未命名的节点,因为您是客户端,所以不知道它叫什么名称。在它添加到容器后,服务器将为它提供一个身份,让您知道它叫什么。
图 2. 向容器添加新资源
接下来请注意,Turtle 使用了一个任意命名空间,并描述所创建的资源的词汇表。这是 LDP 的价值优势之一。使用任何词汇表的任何类型的任何资源,都可以在 LDPC 中存储和管理。如果单击 POST ,这个 Turtle 会发送到服务器来存储在容器中。您可以自由地添加这个虚假错误的更多元数据,以查看该方法有多灵活。
添加错误后,您应看到 /r/ 文件夹与新资源之间有一个链接。除了可视表示,您还会看到该连接也会在容器数据中传播。Turtle 现在看起来如 清单 1 中所示。请注意,新资源没有使用 contains
关系的链接。因为发回大型容器中包含的所有资源可能很麻烦,所以 LDP 的一种可选的页码扩展使客户端能够轻松地按需浏览整个集合。
清单 1. 反映新资源的 LDPC
<http://localhost:3000/r/> a <http://www.w3.org/ns/ldp#Resource>, <http://www.w3.org/ns/ldp#RDFSource>, <http://www.w3.org/ns/ldp#Container>, <http://www.w3.org/ns/ldp#BasicContainer>; <http://purl.org/dc/terms/title> "LDP.js root container"; <http://www.w3.org/ns/ldp#contains> <http://localhost:3000/r/res1434238382253>.
我的 LDP 实例中的新资源称为 http://localhost:3000/r/res1434238382253
(您的资源很可能包含不同的标识符)。可以想象,在发现此资源时,您无需专门了解如何与它交互。它就像其他任何资源一样:您发出一个 GET
请求,如 清单 2 中所示。现在,您已经了解了资源、它是什么 ( http://www.w3.org/ns/ldp#Resource
)、您可以对它做什么,以及更加特定于领域的表示。
清单 2. 请求新资源
> http get http://localhost:3000/r/res1434238382253 HTTP/1.1 200 OK Allow: GET,HEAD,DELETE,OPTIONS,PUT Connection: keep-alive Content-Type: text/turtle Date: Sat, 13 Jun 2015 23:54:23 GMT ETag: W/"2d1e900102c0c08e6d6a5a558c41b1e8" Link: <http://www.w3.org/ns/ldp#Resource>; rel="type", <http://localhost:3000/constraints.html>; rel="http://www.w3.org/ns/ldp#constrainedBy" Transfer-Encoding: chunked Vary: Accept X-Powered-By: Express <http://localhost:3000/r/res1434238382253> a <http://example.org/vocab/bugtracker#Bug>; <http://purl.org/dc/terms/title> "Product C crashes when shutting down."; <http://example.org/vocab/bugtracker#isInState> "New".
回页首
LDP 还有许多功能,但我目前介绍的知识已足够您了解这些额外的需求对生态系统的作用。您可以使用任意术语,自由地创建您想要的任何类型的资源。您可以将 FOAF 和 Dublin Core 等通用词汇表与更加特定于领域的概念相结合,比如问题、需求和测试。本教程重点介绍了基于 RDF 的资源 (LDP-RS),但 LDPC 也可以存储非基于 RDF 的资源 (LDP-NR),比如图像、电子表格和文档。
这种特性组合支持将组织、它的员工、软件需求、工件、代码、测试和测试结果结合在一起。所有这些元素都可以通过任意工具和客户端,使用标准联系起来。在本系列的最后一篇教程中,我将使用和扩展这些想法,演示 OSLC 术语、工作流和实际活动的一个简单实用的示例。