IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  Web development | Open source  >

使用 PHP 在 CICS 上构建 REST 服务

developerWorks
前一页第 3 页,共 10 页后一页

文档选项

样例代码


对本教程的评价

帮助我们改进这些内容


从 PHP 调用书库应用程序

使 PHP 可以访问 COMMAREA

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

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

下面的步骤需要使用 Java SDK,并假设在系统 PATH 上可以使用 javajavac 命令。您可以在工作台上执行它们,或直接在 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 rdwbin

要了解更多信息,请阅读 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 个步骤:

  1. 在链接到程序之前准备好 COMMAREA。
  2. 链接到程序。
  3. 从 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 编码页面。要更多地了解 CA1S 中的编码注意事项和配置选项,请阅读 CA1S 文档

在示例脚本下载中提供的脚本为 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 环境,它是一个非常有用的工具。





回页首



前一页第 3 页,共 10 页后一页
    关于 IBM 隐私条约 联系 IBM 使用条款