使用 PHP 在 CICS 上构建 REST 服务


CICS? Transaction Server? (TS) 是一个强大的事务管理器,它的特点是能够快速处理大量数据。SupportPac CA1S 借助 IBM WebSphere? sMash 技术,使用 PHP 脚本功能和与 REST 相关的特性增强 CICS TS。本教程演示如何使用 PHP 快速轻松地处理 CICS 程序,并将其公开到 Web。如果您是 PHP 开发人员,那么想想如何利用您的技术在 CICS 中与企业资产进行交互;如果您是 CICS 开发人员,那么看看 PHP 如何为管理现有资源提供一种简单便捷的方式。

  开始之前

  本教程展示如何使用 CICS SupportPac CA1S 和 PHP 快速在 Web 上公开 CICS COMMAREA 程序。PHP 是一种简单强大的语言,用于快速开发 Web 应用程序。您将使用 REST 和 JavaScript Object Notation (JSON) 创建一个 Web 服务,并确保各种客户端能够方便地使用它,比如 Asynchronous JavaScript and XML (Ajax) 前端、其他 Web 服务和混搭应用程序。

  本教程的示例 CICS COMMAREA 程序(见 下载)是一个用 COBOL 编写的简单书库应用程序。它在 VSAM 文件中包含一个图书列表,您可以在这个列表上添加、删除条目,或将图书标记为已借出或已返还。

  在本教程中您将:

  在 CICS 系统上设置书库应用程序。

  了解如何通过 PHP 调用 CICS COMMAREA 程序。

  了解 CA1S 中能够简化 REST 式 Web 服务创建的特性。

  将书库程序公开为 REST 式 Web 服务。

  先决条件

  为了从本教程获取最大收益,您应该具有 PHP 语言的基础知识,并熟悉 CICS 管理或 CICS 程序的开发。如果要详细了解 CICS,请访问 CICS TS 3.2 Information Center。您应该阅读 CA1S 用户指南的介绍部分,它简单概括了 CA1S 的用途和 REST 的原则。

  CICS 环境

  为了完成本教程的示例,您需要一个 CICS 环境,并且必须满足 CA1S 下载页面 列出的条件。

  根据 CA1S 用户指南 提供的说明,下载并安装 CA1S SupportPac。根据指南中的说明,调用 HelloCICS.php 脚本检测您的安装。

  工具

  所有文本编辑器都可以用来编写 PHP 脚本。您可以使用 IDE,比如 Eclipse PDT。

  您需要一个将 PHP 脚本从工作台传输到 CICS 服务器的机制,比如一台 FTP 客户机或针对 Eclipse 的 Target Management 插件。

  为了测试 REST 式 Web 服务,您需要一个简单的 REST 客户端(比如 Poster add-on for Mozilla Firefox),用于发出 GET、POST、PUT 和 DELETE HTTP 请求。

  在 CICS 中设置书库应用程序

  这个部分概述在 CICS 中安装示例 LIBRARY 应用程序所需的管理任务,并描述如何从客户端上对该程序使用 COMMAREA 接口。必须使用这个接口编写用于访问书库程序的 PHP 脚本。

  设置书库应用程序的步骤

  书库应用程序要求创建并填充一个 VSAM 文件,并编译一个 COBOL 程序。同时也需要该文件和程序的 CICS 资源定义。下面详细描述这些步骤。假设您具有关于 CICS 配置流程的基础知识。

  除了 PHP 之外(后文将就此进行讨论),还没有其他可以调用 LIBRARY 程序的机制(尽管您可以开发一个)。因此,用于验证文件和程序是否正确安装的方法还很少。由于这个原因,设置说明建议使用 CEMT 手动打开文件和加载程序,这样做可以检查这些定义。

  创建和定义 VSAM 文件

  示例书库程序需要一个 VSAM KSDS,用于保存目录内容。代码归档中的 library/jcl/LIBFILE 文件包含用于删除和重新创建所需数据集的示例 JCL,并使用适合的原始数据填充数据集。这个 JCL 必须传输到 z/OS? 系统的适当位置,并做出以下更改:

  使用适合您的环境的 JOB 卡替换原来的 JOB 卡。

  使用适合您的系统的数据集名称替换原来的数据集名称的所有实例(P8BUILD.CICS650.LIBRARY.LIBFILE)。在后面的 CICS FILE 定义中需要用到这里选择的名称。

  可选。您可以编辑书库的原始数据,保持一致性和完整性(见下面的解释)。

  下面的步骤将完成 VSAM 文件的创建和定义:

  提交前面修改的 LIBFILE JCL,并检查是否成功执行。

  登录 CICS,并使用带有以下属性的 CEDA(或其他机制)创建一个 CICS FILE 定义:

表 1. 创建 VSAM FILE 定义时使用的属性

属性
FILE LIBFILE
GROUP LIBRARY
DSName <As specified in LIBFILE JCL>
RECORD FORMAT F
ADD Yes
BROWSE Yes
DELETE Yes
READ Yes
UPDATE Yes


  安装 LIBFILE 定义,并检查是否成功。

  可选。使用 CEMT,或打开 LIBFILE 并检查是否成功打开:

CEMT SET FILE(LIBFILE) OPEN

  建议使用这个步骤检查是否正确创建和定义文件,因为设置的检查可能不全面。

  编译和定义 COBOL 程序

  LIBRARY 应用程序的源代码位于 library/cobol/LIBRARY 文件中,用于编译源代码的示例 JCL 位于 library/jcl/LIBCOBOL 文件中,它们都包含在本文提供的示例代码压缩文件中。必须将这些文件传输到您的 z/OS 系统的适当位置,并且需要根据以下说明修改 LIBCOBOL JCL。提供的版本如下所示:


清单 1. 用于编译 LIBRARY 程序的 JCL
//LIBCOBOL JOB USER=P8BUILD,CLASS=A,MSGCLASS=A,NOTIFY=&SYSUID 
// JCLLIB ORDER=CTS320.CICS650.SDFHPROC 
//COMPCOB EXEC DFHZITCL, 
//    PROGLIB=P8BUILD.CICS650.LOAD, 
//    LNGPRFX=PP.COBOL390.V340, 
//    CBLPARM=('NODYNAM,LIB,ADATA,RENT', COMPILER OPTIONS 
//     'CICS(''COBOL2,SP'')'),    TRANSLATOR OPTIONS 
//    INDEX=CTS320.CICS650, 
//    LIBPRFX=PP.ADLE370.ZOS190, 
//    DSCTLIB=P8BUILD.CICS650.COPY 
//COBOL.SYSIN DD DSN=P8BUILD.CICS650.COBOL(LIBRARY),DISP=SHR 
//COBOL.SYSADATA DD DSN=P8BUILD.CICS650.COBADATA(LIBRARY), 
//    DISP=SHR 
//LKED.SYSIN DD * 
  NAME LIBRARY(R) 
/* 

  需要做出以下更改:

  提供一个适合的 JOB 卡。

  更改所有数据集名称和前缀,让它们适合您的 z/OS 和 CICS。

  确保 COBOL.SYSADATA DD 定义指向一个带有可变长度记录的 PDS 成员,它适合保存 ADATA 输出。请参考 COBOL 编译器文档了解更多细节。

  通过以下步骤完成 LIBRARY 应用程序的编译和安装:

  提交前面修改的 LIBCOBOL JCL,并检查是否成功执行。

  登录 CICS 并使用 CEDA(或其他机制)创建一个具有以下属性的 CICS PROGRAM:

表 2. CICS PROGRAM 属性

属性
PROGRAM LIBRARY
GROUP LIBRARY
Language COBOL


  安装 LIBRARY 程序定义并检查是否成功。

  可选。对 LIBRARY 程序使用 CEMT 或 NEWCOPY,并检查它是否加载: CEMT SET PROGRAM(LIBRARY) NEWCOPY

  建议使用这个步骤检查该程序是否正确编译和定义,因为设置的检查可能不全面。

  如何使用 COBOL Library 应用程序

  CICS COMMAREA 应用程序的一个约定是,当被调用时,将向它传递一个包含输入数据的储存区域,有时也包含需要执行的操作的说明。在处理完成之后,将使用输出数据和来自该操作的响应代码覆盖存储区域。COMMAREA 存储区域的格式通常在一个 COBOL Copybook 中定义,后者包含在目标程序及其调用方中。

  要使用这样的 CICS 程序,您不仅要了解该程序输入输出时所需的 COMMAREA 格式,还需要了解它支持的操作、期望的输入输出数据和响应代码。在 CA1S 中,由 JZOS 生成的记录类执行 COMMAREA 的数据结构的构建和解释。不过,PHP 应该负责设置所需的输入字段,并使用 JZOS 生成的 API 提取合适的输出数据。

  本文提供的示例 Library 应用程序遵循这个标准模式,因此 PHP 程序员需要了解生成的 JZOS 记录类和 COMMAREA 接口的使用,以便能够从 PHP 脚本正确地调用 Library 应用程序。

  书库的 COMMAREA 格式

  下面展示了定义书库应用程序使用的 COMMAREA 格式的 COBOL 数据定义:


清单 2. 书库应用程序的 COBOL 数据定义
   01 DFHCOMMAREA.                       
   *  LIBRARY COMMAREA structure                
     03 LIB-REQUEST-TYPE     PIC X(6).          
     03 LIB-RETURN-CODE      PIC 9(2).          
     03 LIB-ITEM-COUNT      PIC 9(4).          
     03 LIB-BOOK-ITEM OCCURS 24 TIMES.            
       05 BOOK-ITEM-REF     PIC 9(4).         
       05 BOOK-TITLE       PIC X(20).         
       05 BOOK-AUTHOR      PIC X(20).         
       05 BOOK-LOAN-STATUS    PIC 9(2).         
         88 BOOK-ONLOAN VALUE 1.              
         88 BOOK-UNLENT VALUE 0.              
       05 BOOK-BORROWER     PIC X(20).         
       05 FILLER         PIC X(14). 

  JZOS 记录生成器工具(随后介绍)将清单 2 中的定义转换成可以从 PHP 使用的 API,以从 COMMAREA 获取或设置字段。COBOL 中使用的字段名和 PHP 方法之间有一个直观的映射,因此可以将它们关联起来。

  书库应用程序的使用

  您只需了解目标 CICS 程序所需的 COMMAREA 格式,就能够正确调用该程序。此外,还需要程序的使用信息,比如程序支持什么操作,如何在 COMMAREA 中指定它们,每个操作的其他输入和输出,以及可能的结果和响应。清单 3 给出了书库应用程序的参考使用信息。

  因为本文提供了调用书库应用程序所需的示例 PHP 脚本,所以您在首次设置时不需要这些信息,但您在理解、修改和重新实现脚本时,必须参考这些信息。

  LIB-REQUEST-TYPE 是一个包含 6 个字符的文本字段,它决定书库应用程序将要执行的操作。在调用书库应用程序之前,必须将这个字段设置为以下值之一:


表 3. 书库应用程序的 LIB-REQUEST-TYPE 字段

LIB-REQUEST-TYPE 书库操作
LIST 通过数组 LIB-BOOK-ITEM 返回一个列出库中所有图书的列表。
库的最大容量最多只能包含 24 个元素。每个项都包含相关图书的完整细节。现有的图书数目由 LIB-ITEM-COUNT 返回。
QUERY 在第一个元素 LIB-BOOK-ITEM(1) 中返回指定图书的细节。
在 BOOK-ITEM-REF(1) 中输入所请求的图书的索引(参考)。
ADD 向书库添加一本新书;在 LIB-BOOK-ITEM(1) 中提供细节。假设库中还有空间(最大图书储存数为 24 本),新书的索引由 BOOK-ITEM-REF(1) 返回。
DELETE 从库中(如果存在的话)删除由 BOOK-ITEM-REF(1) 标识的图书。
BORROW 将由 BOOK-ITEM-REF(1) 指定的图书标记为正在借阅,并向这本书的记录中添加借阅者的名称(BOOK-BORROWER(1))。
RETURN 将指定的书标记为未借阅,并从这本书的记录中删除借阅者的名字。由 BOOK-ITEM-REF(1) 标识将要返回的图书。

  对于图书返回,书库应用程序根据请求操作的结果将 LIB-RETURN-CODE 设置为 2 位数字值:


表 4. 书库应用程序的返回代码

LIB-RETURN-CODE 含义
文件名 操作 条件
LIBRARY-OK 0 All 成功完成。
LIBRARY-NOTFOUND 1 All except LIST, ADD 在库中未找到指定的图书。
LIBRARY-ONLOAN 2 BORROW 图书已经借出。
LIBRARY-DUPLICATE 3 Not used 不应该发生。
LIBRARY-INVREQ 4 All 无效的用户请求。
LIBRARY-FULL 5 ADD 书库已满(最多只能储存 24 本书!)
LIBRARY-ERROR 99 All 意外处理错误。

  在书库应用程序的 level-01 数据部分 (LIBRARY-CONSTANTS) 定义可用的请求类型和返回代码,这意味着可以通过 JZOS 记录生成器在 PHP 脚本中使用它们,实现方法与 COMMAREA 数据类似。

  总体而言,如果要从 PHP 调用 CICS 程序,PHP 程序员需要具有等价于表 4 的信息,这些信息通常由维护该程序的 CICS 程序员以适当的形式提供。

  从 PHP 调用书库应用程序

  使 PHP 可以访问 COMMAREA

  在 COBOL 程序中定义 COMMAREA 并生成 ADATA 之后,下一步就是创建用于表示 COMMAREA 的 Java? 类。这些类使 PHP 脚本可以访问 COMMAREA。

  这些 Java 类仅需生成一次:只要 CA1S 可以使用这些类,就可以编写任意脚本通过它们与 COBOL 程序交互。然而,如果修改 COBOL 程序导致改变了 COMMAREA,那么就要重新生成 ADATA 和 Java 类,并根据需要修改 PHP 脚本。

  下面的步骤需要使用 Java SDK,并假设在系统 PATH 上可以使用 java 和 javac 命令。您可以在工作台上执行它们,或直接在 CICS 系统上执行它们。

  1. 生成 COMMAREA 类的源代码

java -cp jzos_recgen.jar com.ibm.jzos.recordgen.cobol.RecordClassGenerator genCache=false 
adataFile=LIBRARY symbol=DFHCOMMAREA class=Library_Commarea package=library outputDir=. 

  我们看看以上命令的各部分的作用:

java -cp jzos_recgen.jar com.ibm.jzos.recordgen.cobol.RecordClassGenerator 

  这将调用 JZOS 记录生成器,这是一个包含在 jzos_recgen.jar 文件中的 Java 程序。这个文件包含在 CA1S 中,在 alphaWorks 的 IBM JZOS Batch Toolkit for z/OS SDKs 站点上可以找到最新的版本。

  为什么运行 JZOS 记录生成器时遇到 Java 异常?

  在使用 FTP 获取 ADATA 之前,记得运行命令 quote site rdw 和 bin。

  要了解更多信息,请阅读 JZOS 文档 “Running the COBOL RecordClassGenerator”,即 CA1S 包中的 “JZOS Cobol Record Generator Users Guide.pdf”。

genCache=false 

  这个选项确保生成的 Java 代码不尝试缓存 COMMAREA 字段的值。CA1S 需要用这个选项与生成的类正确地进行交互。

adataFile=LIBRARY 

  这指定前一小节中的 ADATA 文件的路径。

symbol=DFHCOMMAREA 

  这指定需要为它生成类的 COMMAREA 的名称。

class=Library_Commarea 

  这指定生成的 Java 类的名称。

package=library 

  这指定生成的 Java 类所在的包。

outputDir=. 

  这指定在文件系统上写入 Java 类的路径。

  2. 为表示 COBOL 常量的类生成 Java 源代码

  在示例书库应用程序中,COBOL 程序使用的常量(对于操作名和响应代码)是在 WORKING-STORAGE 部分的数据结构中定义的。这意味着可以生成表示这些常量的 Java 类,并以类似于表示 COMMAREA 类的方式从 PHP 使用它们。在这个例子中,是为了在需要时获取已定义常量的值。

java -cp jzos_recgen.jar com.ibm.jzos.recordgen.cobol.RecordClassGenerator genCache=false 
adataFile=LIBRARY symbol=LIBRARY-CONSTANTS class=Library_Constants package=library 
outputDir=. 

  这种方法的优势是可以使用 PHP 反射检查可用的常量名,因此 PHP 程序员不需要直接引用在 COBOL 中定义的值。记住,可以对 LIBRARY 应用程序执行该操作,这是由定义常量的方式决定的,并且不能保证始终可用;例如,在 COBOL 源代码中嵌入了硬编码的值。

  在本文提供的 PHP 脚本中,采用一种混合的方法,其中一些常量以字面的形式使用(比如操作名),另一些常量则使用生成的 Java 类提取(数字响应代码)。

  3. 通过编译 .java 源文件创建 Java 类文件

  生成的 Java 源文件将储存在前面指定的 outputDir 的子目录中(与包名对应)。使用 javac 按以下方式编译源文件:

javac -cp jzos_recgen.jar library/* 

  4. 使 CA1S 可以使用类文件

  现在,library 目录已经包含已编译的类。这些类必须在 Java 类路径中,CA1S 才能使用它们。如果您在工作台中生成这些类,则需要将目录转移到服务器(例如使用 FTP)。

  Java 类路径由 CA1S 使用的 JVMPROFILE 的 CLASSPATH_SUFFIX 属性决定。CA1S 中默认的 JVMPROFILE(名为 CA1SJVMP)已经配置为在 CLASSPATH_SUFFIX 中包含 ca1s/work/classes/ 目录:

CLASSPATH_SUFFIX=/u/p8build/ca1s/config/ini:\ 
         /u/p8build/ca1s/p8/jars/p8api.jar:\ 
         /u/p8build/ca1s/p8/jars/p8.jar:\ 
         /u/p8build/ca1s/p8/jars/p8cics.jar:\ 
         /u/p8build/ca1s/work/classes:\ 
         /usr/lpp/db2910/classes/db2jcc.jar:\ 
         /usr/lpp/db2910/classes/db2jcc_javax.jar:\ 
         /usr/lpp/db2910/classes/db2jcc_license_cisuz.jar 

  因此,如果您使用 JVMPROFILE CA1SJVMP,那么需要将 library 目录复制到 ca1s/work/classes/。或者更改 CLASSPATH_SUFFIX,使其包含一个包含 library 目录的目录或 JAR 文件。

  注意,表示包名的目录结构必须位于类路径位置之下。因此,如果您使用 ca1s/work/classes/,则需要复制 library 目录,使类位于 ca1s/work/classes/library 之下(而不是 ca1s/work/classes/)。

  最后,退出 JVM 以确保 CA1S 能够使用新的类。

  从 PHP 代码访问书库程序

  代码

  调用 COMMAREA 程序包含 3 个步骤:

  在链接到程序之前准备好 COMMAREA。

  链接到程序。

  从 COMMAREA 获取链接的结果。

  为了进行演示,清单 3 的脚本通过调用书库程序获取图书列表,然后打印它们:


清单 3. 从 PHP 调用 CICS Commarea 程序
<?php 
// Step 1: create and prepare the COMMAREA instance 
java_import('library.Library_Commarea'); 
$COMMAREA = new Library_Commarea(); 
$COMMAREA->setLibRequestType('LIST'); 
 
// Step 2: create the program instance and invoke it using the COMMAREA 
$program = new CICSProgram('LIBRARY'); 
try { 
 $program->link($COMMAREA); 
} catch (CICSException $e) { 
 echo 'Error: ' . $e->getMessage(); 
 return; 
} 
 
// Step 3: retrieve the result of the link from the COMMAREA 
$totalBooks = $COMMAREA->getLibItemCount(); 
echo "Total number of books: $totalBooks <br/>"; 
 
for ($i=0; $i<$totalBooks; $i++) { 
 $book = $COMMAREA->getLibBookItem($i); 
 $title = $book->getBookTitle(); 
 $author = $book->getBookAuthor(); 
 echo "Book $i is '$title' by '$author'. <br/>"; 
} 
?> 

为何在浏览器中访问脚本时看到的是乱码?

  如果在错误的编码页面中编码脚本将发生这种错误。默认情况下,CA1S 中的 PHP 运行时被配置为使用 UTF-8 编码。因此,如果您在 Windows? 或 Linux? 工作台和 CICS 服务器之间传输脚本,一定要设置为 “binary” 模式,这样脚本就不会在传输期间被转换为 EBCDIC 编码页面。

  在示例脚本下载中提供的脚本为 library/scripts/library.php。如果您将这个脚本传输到 CICS 系统的 ca1s/work/scripts/library.php 中,并从浏览器访问它,您将看到一个图书列表:

Total number of books: 18 
Book 0 is 'PHP for Beginners ' by 'Rob Nicholson '. 
Book 1 is 'Project Management ' by 'A N IBMer '. 
Book 2 is 'Easy Z Specification' by 'Jonathan '. 
Book 3 is 'REST Protocol Design' by 'Zoe, Ant & Rob '.  
etc... 

  现在,我们仔细查看代码中包含的 3 个步骤。


准备 COMMAREA
java_import('library.Library_Commarea'); 

  在 CA1S 中为 PHP 运行时内置的 java_import() 函数将加载一个 Java 类,从而使这个类可以在 PHP 中使用。在上面的代码中,我们将加载表示前面创建的书库 COMMAREA 类的 Java 类。

$COMMAREA = new Library_Commarea(); 

  然后,创建这个类的一个实例。这个实例被用作调用的输入和输出数据的容器。

$COMMAREA->setLibRequestType('LIST'); 

  最后,在第三行代码中,我们在 COMMAREA 上设置一些输入数据。setLibRequestType 方法特定于表示本教程的 COBOL 程序的 COMMAREA 的 Java 类:它定义我们希望对书库执行的操作,在这个例子中,是获取一个包含所有图书的列表(LIST)。查看 使用反射研究 COMMAREA,了解如何使用 PHP 发现关于 Java 类的所有方法。


链接到程序
$program = new CICSProgram('LIBRARY'); 

  首先,我们创建内置类 CICSProgram 的一个实例,它表示我们将要与之交互的 CICS 程序。CICS 程序的名称指定为构造器的参数,在这个例子中为 “LIBRARY”。如果重命名程序,那么也要更改这个参数。

  为什么看到的不是我想要的结果,而是 “com.ibm.cics.server.InvalidProgramIdException: CICS PGMIDERR Condition”?

  仔细检查传递到 CICSProgram 构造器的参数(表示安装在 CICS 系统的 COBOL 程序的名称)。

$program->link($COMMAREA); 

  CICSProgram 类的 link 方法触发 CICS 程序的执行。如果提供单一的 COMMAREA 参数(如本例),它将被 CICS 程序用作输入和输出数据的容器。您也可能提供两个不同的 COMMAREA 参数,对于这种情况,第一个参数用于包含输入数据,第二个参数用于包含输出数据。此外,也可以不提供参数,当 CICS 程序没有输入和输出时,这种做法很有用。

try / catch block 

  如果链接失败,或被链接的程序异常终止,那么 link 方法将抛出一个 CICSException。异常对象中的 getMessage() 方法描述失败细节,包括基本 Java 异常的类型。例如,如果将一个无效程序名指定为 CICSProgram 构造器的参数,以上代码将输出:

Error: com.ibm.cics.server.InvalidProgramIdException: CICS PGMIDERR Condition 

Retrieving data from the COMMAREA
$totalBooks = $COMMAREA->getLibItemCount(); 

  在 link() 成功返回之后,COMMAREA 就包含调用的输出。在上面的 PHP 脚本的步骤 3 中,我们使用各种特定于 Library_Commarea 类的方法来获取图书的总数,然后遍历图书列表,并输出每本书的标题和作者。

  使用 PHP 反射研究 COMMAREA

  如果要在链接之前在 COMMAREA 上设置输入数据,随后从 COMMAREA 获取输出数据,那么需要了解 COMMAREA 类的 setter 和 getter 方法。如果您没有这些方法,可以通过 PHP 反射轻松获得。

  例如,下面的脚本使用 PHP 反射类获取在 Library_Commarea 类中可用的方法列表:


清单 4. 使用反射,第 1 部分
<?php 
java_import('library.Library_Commarea'); 
$COMMAREA = new Library_Commarea(); 
$rc = new ReflectionObject($COMMAREA); 
foreach ($rc->getMethods() as $method) { 
 echo $method->getName() . '<br/>'; 
} 
?> 

  清单 4 中的脚本的输出为:

Library_Commarea 
__tostring 
setLibItemCount 
getLibReturnCode 
setLibRequestType 
setLibReturnCode 
getByteBuffer 
getLibRequestType 
getLibBookItem 
getLibItemCount 

  除了 Library_Commarea() 方法(构造器)和 getByteBuffer() 方法(提供对包含 COMMAREA 数据的原始字节数组的访问)之外,其他方法都是 COMMAREA 字段的 getter 和 setter 方法。在最初脚本中使用的方法用粗体表示。

  一些 getter 方法返回复杂的数据结构,比如以上的 getLibBookItem() 方法,它返回一个表示一本书的对象。可以将这种技术用于这些数据结构中,找到可以访问的字段。例如,在这里我们使用 PHP 函数 get_class_methods()确定一本书的哪些字段是可以访问的:


清单 5. 使用反射,第 2 部分
<?php 
// Step 1: create and prepare the COMMAREA instance 
java_import('library.Library_Commarea'); 
$COMMAREA = new Library_Commarea(); 
$COMMAREA->setLibRequestType('LIST'); 
 
// Step 2: create the program instance and invoke the program using the COMMAREA 
$program = new CICSProgram('LIBRARY'); 
$program->link($COMMAREA); 
 
// Investigate the fields available on a book object 
$book = $COMMAREA->getLibBookItem(0); 
print_r(get_class_methods($book)); 
?> 

  清单 5 中的脚本的输出为:

Array 
( 
  [0] => LibBookItem 
  [1] => getBookTitle 
  [2] => setBookItemRef 
  [3] => isBookOnloan 
  [4] => getBookAuthor 
  [5] => isBookUnlent 
  [6] => getByteBuffer 
  [7] => setBookAuthor 
  [8] => setBookBorrower 
  [9] => getBookLoanStatus 
  [10] => getByteBufferOffset 
  [11] => getBookBorrower 
  [12] => __tostring 
  [13] => getFiller_1 
  [14] => getBookItemRef 
  [15] => setBookTitle 
  [16] => setFiller_1 
  [17] => setBookLoanStatus 
) 

  使用 phpinfo() 诊断类路径

  如果您看到表示找不到 COMMAREA 类的警告或错误,请检查 Java 类路径是否正确,它必须具有一个包含 library 目录(包含生成的类)的 JAR 文件或目录。

  这可以使用 PHP phpinfo() 函数直接完成:

<?php 
phpinfo(); 
?> 

  在浏览器中访问这个脚本能够显示很多信息,包括完整的类路径:


图 1. 使用 phpinfo() 检查 Java 类路径

  classpath.png

  phpinfo() 的最常见用法是检查 PHP 环境,它是一个非常有用的工具。

  CA1S 中的 REST 基础

  SupportPac CA1S 中的 REST 式事件处理程序

  概述

  WebSphere sMash 引入了一组约定,它们简化了 REST 式 Web 服务的创建。SupportPac CA1S 采用了这些约定的其中一部分,并且在 CA1S 文档中详细描述,但可概括为:

  可将 CA1S 配置为以 REST 方式处理某些路径的请求。在默认的 CA1S 安装中,这个特性适用于 /ca1s/resources 下的路径。

  当在这种路径上的请求被处理时,将按照以下方式从 URI 发出关于目标源的信息:

http://<host>/ca1s/resources/<resourceName>[/<resourceID>[/<…more/resource/info…>]] 

  将查找与资源名称对应的资源处理程序脚本。PHP 引擎将执行该脚本,然后尝试在脚本内部调用一个特定的方法,这取决于请求的 HTTP 方法和 URI 是否在资源名称之后包含一个标识符。

  表 5 显示了从 HTTP 请求类型到将要调用的方法的映射,假设资源的名称为 “book”:


表 5. REST 式事件处理程序方法

请求 URI HTTP Method Handler method invoked in ca1s/work/resources/book.php
集合 URI,例如
http://<host>/ca1s/resources/book
GET book::onList()
  POST book::onCreate()
  PUT book::onPutCollection()
  DELETE book::onDeleteCollection()
成员 URI,例如
http://<host>/ca1s/resources/book/10
GET book::onRetrieve()
  POST book::onPostMember()
  PUT book::onUpdate()
  DELETE book::onDelete()

  资源处理程序脚本不需要实现表 5 中的所有方法。如果没有找到特定事件的方法,也不会引起错误。最常实现的事件处理程序是与资源上的 List、Create、Retrieve、Update 和 Delete(LCRUD)操作对应的事件的处理程序,在表 5 中用粗体表示它们。

  示例

  清单 6 中的示例为每个事件输出不同的字符串:


清单 6. 资源处理程序脚本的主体结构
<?php 
class book { 
 function onList() { 
  echo 'LIST all books!'; 
 } 
 
 function onCreate() { 
  echo 'CREATE a book!'; 
 } 
 
 function onRetrieve() { 
  echo 'RETRIEVE a book!'; 
 } 
 
 function onUpdate() { 
  echo 'UPDATE a book!'; 
 } 
 
 function onDelete() { 
  echo 'DELETE a book!'; 
 } 
} 
?> 

  如果要测试它,请将以上的脚步复制到您的 CICS 系统的 ca1s/work/resources/book.php(注意,在脚本中声明的类名必须与脚本文件名匹配)。然后使用 REST 客户端(比如 Poster add-on for Firefox)通过不同的 HTTP 方法访问它(是否对 URI 使用标识符)。您将看到事件处理程序被正确触发。例如:


图 2. 图书资源中带有标识符的 GET 请求触发 onRetrieve() 事件处理程序


图 3. 图书资源中不带标识符的 POST 请求触发 onCreate() 事件处理程序

  事件处理程序未被调用?

  确认以下所有表述都是相同的(它们都表示资源名):

  在 ‘ca1s/resources/’ 前缀之后的请求 URI 的第一个路径组件

  针对 .php 扩展的资源处理程序脚本的文件名

  在脚本中定义的类的名称

  使用 zget() 访问请求数据

  脚本可能使用 CA1S 内置的 zget() 函数访问入站请求的各种属性。其中的例子包括:

  入站请求的主体作为字符串,从请求编码转换为 PHP 运行时编码:

$data = zget('/request/input/transcoded');

  查询字符串参数(以及 POST 和 PUT 参数,如果它们经过了格式编码):

 $value = zget('/request/params/<paramName>'); 

  在入站 URI 指定的请求资源的 ID:

 $id = zget('/request/params/<resourceName>Id'); 

  资源 ID 之后的 URI 部分(如果可用的话):

 $data = zget('/event/pathInfo'); 

  如果要使用 zget(),请按照以下方式修改 book.php 中的 method book::onUpdate():

function onUpdate() { 
 $id = zget('/request/params/bookId'); 
 $data = zget('/request/input/transcoded'); 
 echo "You attempted to update book $id with data $data"; 
} 

  然后,使用 PUT 请求访问一个特定的图书资源,以触发更新事件。


图 4. 使用 Poster 测试 zget

  zget() 函数基于 WebSphere sMash 中的 Global Context 特性。CA1S 文档描述了 zget() 在 CA1S 中提供的完整函数,并且与 WebSphere sMash 中的版本进行了比较。您还可以使用 PHP 的标准机制访问请求数据,比如 使用 PHP 在 CICS 上构建 REST 服务 - 站长学院

使用 PHP 在 CICS 上构建 REST 服务

2010-12-28 17:59:00查看学习心得
{GetProperty(Content)}
« 
» 

Copyright © 2016 phpStudy | 豫ICP备2021030365号-3