创建 OpenACS 软件包
上个月,我们继续探索 OpenACS,了解了如何使用 APM(ArsDigita 软件包管理器)将各个应用程序打包在一起。每个 OpenACS 应用程序通常将数据库表与服务器端程序结合在一起,这意味着安装或升级软件包比复制一些文件要复杂得多。正如我们上个月所见,APM 应用程序使得安装软件包,然后在一个或多个 URL 下实例化它相对容易。
如果您只关心使用现有的 APM,这当然很好。但是大多数 OpenACS 安装都需要新的、自定义的软件包,这些软件包有自己的数据模型和程序。虽然理论上可以在没有 APM 的情况下开发 OpenACS 应用程序,但这样做会使分发您的软件、跟踪版本或标准化您的安装过程变得困难。
本月,我们将介绍如何使用 APM 开发我们自己的简单 Web/数据库应用程序。最终结果是一个其他人可以加载到他们的 OpenACS 系统中的应用程序。
创建新 OpenACS 应用程序的第一步是通过基于 Web 的 APM 程序创建一个新的骨架软件包。默认情况下,此程序仅对具有 OpenACS 系统管理权限的用户可用,因此您可能需要在开始开发工作时请求管理员修改权限。
在大多数 OpenACS 系统上,您可以通过 /acs-admin/apm/ URL 启动 APM 程序。此程序显示所有已安装的 APM,包括每个 APM 的名称、版本和包含的文件数。文件计数通常包括 .sql 文件(用于创建和删除数据库定义)、.tcl 文件(包含 Tcl 程序代码)、.adp 文件(用于类似于 ASP 或 JSP 的 Web 模板)和 .xql 文件(包含 SQL 查询)。但是,APM 可以包含其他文件,包括图像、文本文件,甚至更不寻常的东西,例如 Flash。
正如我们上个月所见,我们可以使用此屏幕作为入口点来安装、检查和修改系统上的软件包。但是,如果我们在列表底部向下滚动并单击“创建新软件包”链接,我们就可以开始创建我们自己的应用程序的过程。
最初的“创建软件包”屏幕要求提供许多参数,这些参数将帮助 APM 创建一个 .info 文件,该文件向系统描述软件包。假设我们想要创建一个最少工作量的“hello, world”应用程序,我们可以填写少量字段
软件包密钥应为 atf-hello。APM 没有命名空间层次结构,但大多数开发人员将他们的姓名(或类似的标识术语)放在软件包名称的前面,以避免冲突。
软件包名称可以是 Hello 或您选择的任何其他名称;开发人员使用它来与其他软件包区分开来。
我们正在开发一个应用程序,而不是服务。
我们的版本号为 0.1d,这意味着它处于开发的早期阶段。
您可以酌情填写或忽略摘要和描述。但是,对于实际应用程序,最好填写这些信息。
完成后,确保选中“写入软件包”指定符框,然后单击页面底部的“创建软件包”按钮。您将被带到此特定软件包的管理屏幕。如果您查看安装 OpenACS 工具包的文件系统上的 packages 子目录,您将看到一个 atf-hello 目录,其中包含一个格式正确的 XML atf-hello.info 文件。
现在 OpenACS 识别了我们的软件包,我们可以开始设计我们软件包的数据模型了。正如所有经验丰富的 Web/数据库开发人员所知,设计表是最困难的部分;一旦您知道它们将如何工作,创建添加、删除和修改数据的应用程序就非常容易了。
我们的应用程序将为我们提供一个简单的留言簿,网站访问者可以在我们的页面上输入评论。(OpenACS 自带一个更通用和强大的工具,可以在网站上的任何页面上执行此操作,但为了学习如何创建软件包,我们将忽略这一点。)我们的数据模型将如下所示
CREATE TABLE atf_hello_postings ( posting_id SERIAL NOT NULL, user_id INTEGER NOT NULL REFERENCES users ON DELETE CASCADE ON UPDATE CASCADE, entry_date TIMESTAMP NOT NULL DEFAULT NOW(), posting TEXT NOT NULL CHECK (posting <> ''), PRIMARY KEY(posting_id) );
从纯技术的角度来看,对于任何使用过 PostgreSQL 的人来说,以前的表定义可能看起来是合理的。我们将 posting_id 设置为整数主键,user_id 设置为外键,一个时间戳字段(包含日期和时间信息),然后是一个文本字段来包含实际的帖子。请注意我们的表名是如何以 atf_hello 开头的,这反映了它在 atf-hello APM 中。保持表名与软件包名称一致是一种原始形式的命名空间管理,但如果每个人都坚持使用它,它就足够好了。
以上在 PostgreSQL 下有效,但不保证在 Oracle 下有效。鉴于 OpenACS 社区以透明地与这两个数据库协同工作而自豪,我们应该怎么做才能避免疏远我们的高端同事呢?
答案是,在安装 atf-hello 软件包时,APM 会查找名为 sql/atf-hello-create.sql 的文件。如果存在这样的文件,则假定它适用于所有支持的数据库。否则,APM 会查找名为 postgresql 和 oracle 的子目录,并在相应的目录中执行 atf-hello-create.sql。因此,如果您的系统使用 PostgreSQL,则上面的 SQL 将保存在名为 sql/postgresql/atf-hello-create.sql 的文件中。官方的 OpenACS 软件包应该开箱即用地与 Oracle 和 PostgreSQL 配合使用,这意味着很少找到仅适用于一个品牌或其他品牌的软件包。(本月专栏中的示例保证仅适用于 PostgreSQL,尽管将它们移植到 Oracle 应该不会太困难。)
OpenACS 还允许我们创建一个清理脚本,名为 sql/PACKAGE-drop.sql,它会删除 create 脚本定义的所有表和存储过程。因此,我们创建了一个名为 sql/postgresql/atf-hello-drop.sql 的文件。
APM 知道如何在首次安装软件包时创建数据模型,但在您进行开发工作时则不知道。因此,要将 atf-hello 安装到数据库中,您需要手动处理它
psql -f atf-hello-create.sql openacs4
当然,这假设 openacs4 是您的 OpenACS 数据库的名称,PostgreSQL 服务器与 psql 客户端在同一台机器上运行,并且您当前的用户名称具有对该数据库的访问权限。
现在我们的数据模型已经安装好了,是时候编写一个使用它的应用程序了。OpenACS 4 引入了一个新的模板系统,该系统构建在 ADP(AOLserver 等效于 ASP 或 JSP)之上,我发现它是 OpenACS 最好的部分之一。
对于非程序员来说,类似于 ASP 的页面比标准的服务器端程序更容易理解。但是,HTML 和程序的混合往往会成为瓶颈,因为设计人员和开发人员无法同时处理该文件。
OpenACS 模板是解决此问题的一个令人耳目一新的解决方案。我们将页面分为两个部分:一部分(.tcl 页面)供程序员使用,另一部分(.adp 页面)供设计人员使用。.tcl 页面以一个契约开始,描述了它期望接收哪些值,以及它将向 ADP 页面提供哪些值。Tcl 页面以调用 ad_return_template 结束,它会查找同名的 .adp 页面,适当地替换变量,然后在该页面上运行 ADP 解析器。
Tcl 页面可以以数据源的形式将值传递给 ADP 页面,数据源是变量的别称。如果 Tcl 页面说
set five 5
ADP 页面可以在任何地方通过将变量名用 @ 符号括起来来检索此值,如 @five@。如果变量 five 没有在页面契约中定义或导出,OpenACS 会产生运行时错误,抱怨不存在这样的变量。
这种职责分离意味着设计人员和程序员可以独立工作,只要页面契约中描述的约定的接口(对于 Tcl 页面的输入和输出)保持不变即可。
OpenACS 附带了大量旨在帮助程序员快速轻松地创建 HTML 表单的函数。为了便于介绍,我们不会使用这些函数;我们将使用简单的原始 HTML。
我们的应用程序将包含两个 URL
一个 URL 将按时间顺序显示 atf_hello_postings 表中的当前条目,以及一个用于输入新帖子的表单。我们将使用 OpenACS 数据库 API,它比原生 AOLserver 数据库 API 更易于使用(并且使我们不必担心线程和数据库池),从数据库中检索结果并将它们放入一个多行变量中。然后,此变量将作为数据源传递给 ADP 页面,并在其中显示。此表单的操作将指向第二个 URL。
另一个是接收 HTML 表单、在数据库中输入新行并将人们重定向回第一个页面的 Tcl 程序。
换句话说,我们的应用程序将需要两个 Tcl 页面和一个 ADP 页面。这些都将放在 atf-hello 下的 www 子目录中;如果该目录不存在,请创建它,并仔细检查它是否与 AOLserver 运行的用户属于同一用户。
第一个 Tcl 页面 (posting.tcl)(如清单 1 所示)不期望任何参数,并导出一个名为 postings 的数据源。Tcl 页面以调用 ad_page_contract 开始,它允许我们注释文件的所有者和用途(在第一个参数中)、我们收到的输入(在第二个参数中,空白 posting.tcl)以及我们导出的数据源(在第三个参数中,由于历史原因命名为属性)。Tcl 页面以调用 ad_return_template 结束,它会查找与当前 .tcl 文件同名的 .adp 文件。
虽然每个数据源实际上都是一个简单的 Tcl 变量,但 OpenACS 模板系统在某种程度上掩盖了这些变量的真实性质,为每个数据源分配一个名称和一个类型(multirow、list、onevalue 或 onerow)。在这种特定情况下,我们的 postings 数据源是一个 multirow,这意味着它将包含来自我们的 SELECT 的多个结果行。db_multirow 过程接受三个参数:应将行读取到的变量的名称、查询的名称和 SQL 本身。
命名查询在 OpenACS 中既是福音也是诅咒。它们是福音,因为它们可以通过将查询放在外部 .xql 文件(适用于特定数据库的 XML 格式文件)中来与多个数据库协同工作。问题在于,OpenACS 首先查找与查询名称关联的 .xql 文件,如果不存在 XML,则仅查看 .tcl 页面中的 SQL。许多 OpenACS 初学者惊讶地发现系统忽略了他们在 .tcl 页面中的 SQL 修改,而是查看了 .xql 页面。
当 posting.tcl 通过调用 ad_return_template 结束时,OpenACS 模板系统会查找 posting.adp。由于我们的 Tcl 页面包含所有的 Tcl 程序代码,因此我们不需要 ADP 页面中的标准 <% %> 标记。但是,我们确实需要一种将我们的数据源转换为 HTML 中可用的内容的方法。
如清单 2 (posting.adp) 所示,OpenACS 模板系统添加了一些标记,使得可以以直接的方式检索在 .tcl 页面中设置的值
我们可以使用 <if> 标记在输出页面中有条件地包含 HTML,该标记比较(使用 eq 和 ne)两个值。在 posting.adp 中,我们将 postings 数据源中的行数(通过查询 @postings:rowcount@)与 0 进行比较。如果没有要显示的行,那么我们什么也不显示。
如果有要显示的行,我们使用 <multiple> 标记遍历它们。在 <multiple> 标记块中,我们可以使用 @NAME.column@ 语法检索单个数据库列,如您在 posting.adp 中看到的那样。
无论我们显示多少行,posting.adp 始终包含一个小的 HTML 表单,该表单将其内容发送到 posting-add 程序。此程序 posting-add.tcl(如清单 3 所示)以 ad_page_contract 开头,该契约声明一个输入变量 (posting_text)。默认情况下,输入变量是强制性的,尽管我们可以通过修改 ad_page_contract 中的条目将它们声明为可选或分配默认值。在这种特定情况下,我们要求 OpenACS 删除我们收到的文本输入中的任何前导或尾随空格。
然后,我们使用内置的 ad_get_user_id 过程检索当前用户 ID,将其分配给 user_id 变量。接下来,我们使用 db_dml 将帖子插入数据库。请注意,我们在 db_dml 中在变量名称之前使用冒号(而不是美元符号);这是 OpenACS 数据库 API 中的标准做法,并确保我们在将数据传递到数据库服务器时不会遇到引号问题。
最后,posting-add.tcl 通过将用户重定向到 posting 来结束,这将调用 posting.tcl 并显示 posting.adp。
我们现在可以返回 APM 并使用我们的模板和数据库创建脚本生成一个软件包。单击 atf-hello 软件包名称,然后单击页面底部的“管理文件信息”链接。现在单击“扫描此软件包中的其他文件”。您应该看到我们安装的 .sql、.tcl 和 .adp 页面的列表。指示所有这些文件都应包含在软件包中,并在返回主 ATF Hello APM 管理屏幕后,单击“生成新的 atf-hello.info 文件”链接。
您现在可以创建一个可以分发给任何其他 OpenACS 用户的 APM 了。单击“生成文件”链接,分发文件信息将指示生成的 APM 的大小。如果您单击此链接,则应将 APM 下载到您的系统。
如何安装某人发送给您的新 APM?最简单的方法是将 APM 放在服务器文件系统上。然后从您的 Web 浏览器中,返回主 APM 页面 (/acs-admin/apm/) 并单击“安装”链接。告诉系统 APM 所在的位置,它将被放置在 packages 目录下。然后,您将能够使用我们上个月检查过的 APM 安装程序来安装它。数据模型将被插入到数据库中,并且 Web 页面将可供任何感兴趣的各方使用。当然,一旦软件包安装到系统中,您就可以使用 ACS 站点地图应用程序在您选择的 URL 下挂载软件包的新实例。
此示例软件包仅触及了 OpenACS 应用程序开发的表面,例如
模板系统带有一个自动表单构建器系统,可以轻松创建 HTML 表单,这些表单自动提供确认屏幕和数据验证。
我们可以通过在软件包的 tcl 目录中定义 Tcl 过程,在启动时将它们加载到 AOLserver 中。
如上所述,命名 SQL 查询使得编写单个 Tcl 程序成为可能,该程序可以透明地访问 Oracle 和 PostgreSQL。
可以使用 OpenACS 上下文概念将软件包的每个实例与其对等实例分开。
每个实例都可以设置自己的参数,使其具有特定于安装的信息。
每个软件包都可以定义(或使用)自己的一组权限,允许您为系统上的用户和组创建自定义权限和自定义访问控制列表。
电子邮件:reuven@lerner.co.il
Reuven M. Lerner 是一位专门从事 Web/数据库应用程序和开源软件的顾问。他的著作《Core Perl》于 2002 年 1 月由 Prentice Hall 出版。Reuven 与他的妻子和女儿住在以色列的莫迪因。