Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

developerWorks Community:

  • Close [x]

Build a RESTful service on CICS with PHP

Robin Fernandes (robin_fernandes@uk.ibm.com), Software Developer, IBM
Photo of Robin Fernandes
Robin Fernandes joined IBM's Java Technology Centre in Hursley, United Kingdom as Software Developer after graduating from Imperial College in 2003. His current focus is a Java-based runtime for PHP, which is used in the CA1S SupportPac and WebSphere sMash. He also regularly contributes test cases and patches to php.net and enjoys experimenting with audio software in his spare time.
Jonathan Lawrence (jlawrence@uk.ibm.com), Software Developer, IBM
Photo of Jonathan Lawrence
Jonathan Lawrence joined IBM's Java Technology Centre in Hursley, United Kingdom as a Software Developer in 2006, after 4 years in Hursley's Software Services department where he was a CICS and Cross-platform Integration Specialist. He designed the CICS integration aspects of the CA1S SupportPac.

Summary:  CICS® Transaction Server® (TS) is a powerful transaction manager designed for rapid, high-volume processing. SupportPac CA1S uses technology from IBM WebSphere® sMash to enhance CICS TS with PHP scripting capabilities and Representational state transfer (REST)-related features. This tutorial shows how you can use PHP to quickly and easily work with CICS programs and expose them on the Web. If you are a PHP developer, find out how you can use your skills to interact with enterprise assets in CICS; if you are a CICS developer, see how PHP provides a simple and agile way to manipulate your existing resources.

Date:  21 Apr 2009
Level:  Intermediate PDF:  A4 and Letter (409 KB | 37 pages)Get Adobe® Reader®

Activity:  12723 views
Comments:  

Invoking the Library program from PHP

Making the COMMAREA available to PHP

After the COMMAREA is defined in the COBOL program and the ADATA has been generated, the next step is to create Java™ classes that represent the COMMAREA. These classes are used to make the COMMAREA accessible from PHP scripts.

You will only need to generate the Java classes once: as soon as the classes are available to CA1S, any number of scripts may be written to use them to interact with the COBOL program. However, if the COBOL program is modified such that the shape of the COMMAREA changes, you will need to regenerate the ADATA and the Java classes, and adapt the PHP scripts as required.

The following steps require a Java SDK and assume that the java and javac commands are available on the system PATH. You execute them on your workstation or directly on the CICS system.

1. Generate the source of the COMMAREA classes

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

Let's describe the purpose of each part of the above command:

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

This invokes the JZOS Record Generator, which is a Java program contained in the file jzos_recgen.jar. This file in included in CA1S, and the most recent version is available on the IBM JZOS Batch Toolkit for z/OS SDKs site at alphaWorks (see Resources).

Why do I get a Java exception when attempting to run the JZOS record generator?

Before retrieving the ADATA using FTP, remember to run the command 'quote site rdw' and 'bin'.

For more information, see the section "Running the COBOL RecordClassGenerator" of the JZOS documentation, which is included in the CA1S package as "JZOS Cobol Record Generator Users Guide.pdf".

genCache=false
             

This option ensures that the generated Java code does not attempt to cache the value of COMMAREA fields. This option is required for CA1S to interact correctly with the generated classes.

adataFile=LIBRARY
             

This specifies the path to the ADATA file obtained in the previous section.

symbol=DFHCOMMAREA 

This specifies the name of the COMMAREA for which to generate the class.

class=Library_Commarea
             

This specifies the name of the resulting Java class.

package=library
             

This specifies the package of the resulting Java class.

outputDir=.
             

This specifies the path to which the Java class will be written on the file system.

2. Generate the Java source for the class representing COBOL constants

In the sample library application, the constants used in the COBOL program (for the operation names and response codes) are defined in a data structure in the WORKING-STORAGE section. This means that a Java class representing these constants can be generated and used from PHP in a similar way to the class representing the COMMAREA, in this case to obtain the values of the defined constants where needed.

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

The advantage of this approach is that PHP reflection can be used to examine the available constant names, and the PHP programmer need not refer directly to the values defined in the COBOL. Keep in mind that this can be done for the LIBRARY application because of the way the constants have been defined, and may not always be possible; for example, where hard-coded values are embedded in the COBOL source.

In the PHP scripts provided with this article, a mixed approach is adopted, where some of these constants are used in their literal forms (for example, the operation names), and some are extracted using the generated Java class (the numeric response codes).

3. Compile the .java source files to create Java class files

The generated Java source will be in the outputDir specified above, in subdirectory library (which corresponds to the package name). Use javac to compile the source files as follows:

javac -cp jzos_recgen.jar library/*

4. Make the class files available to CA1S

The library directory now contains the compiled classes. For CA1S to be able to use them, they must be available on the Java classpath. If you generated the classes on your workstation, you will need to transfer the directory to the server (for example, using FTP).

The Java classpath is determined by the CLASSPATH_SUFFIX attribute of the JVMPROFILE used by CA1S. The default JVMPROFILE in CA1S (named CA1SJVMP) is already configured to include the directory ca1s/work/classes/ in the CLASSPATH_SUFFIX:

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
             

Therefore, if you are using JVMPROFILE CA1SJVMP, you may copy the library directory to ca1s/work/classes/. Alternatively, you may change your CLASSPATH_SUFFIX to include a directory or JAR file that contains the library directory.

Note that the directory structure representing the package name must be preserved under the classpath location. So, if you are using ca1s/work/classes/, copy the library directory itself such that the classes are under ca1s/work/classes/library (and not directly under ca1s/work/classes/).

Finally, phase out your JVMs to ensure the new classes are picked up by CA1S.


Accessing the program from PHP code

The code

The invocation of a COMMAREA program consists of 3 steps:

  1. Preparing the COMMAREA before linking to the program.
  2. Linking to the program.
  3. Retrieving the result of the link from the COMMAREA.

To illustrate, Listing 3 shows a script that invokes the library program to obtain the list of books, then prints them out:


Listing 3. Invoking a CICS Commarea program from PHP


<?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/>";
}
?>

Why do I just see garbage characters when I access a script in my browser?

This can happen if the script is encoded in the wrong code-page. By default, the runtime for PHP in CA1S is configured to expect scripts in the UTF-8 encoding. Therefore, if you transfer scripts between a Windows® or Linux® workstation and your CICS server, be sure to set "binary" mode, so that the scripts are not converted to an EBCDIC code-page during the transfer. For more information on encoding concerns and configuration options in CA1S, see the CA1S documentation.

This script is provided in the sample code download as library/scripts/library.php. If you transfer this script to your CICS system to ca1s/work/scripts/library.php and access it in your browser, you should see a list of books like:

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...
             

Let's examine the three steps in the code in detail.


Preparing the COMMAREA
java_import('library.Library_Commarea');
             

The function java_import(), which is built in to the runtime for PHP in CA1S, loads up a Java class and makes it available for use within PHP. In the code above, we load the Java class representing the library COMMAREA class that we generated previously.

$COMMAREA = new Library_Commarea();
             

Then, we create an instance of this class. This instance will be used as a container for the input and output data of the invocation.

$COMMAREA->setLibRequestType('LIST');
             

Finally, on the third line, we set some input data on the COMMAREA. The method setLibRequestType is specific to the Java class representing the COMMAREA of the COBOL program used in this tutorial: it defines the operation we want to perform against the library, in this case obtain a LIST of all the books. See Investigating the COMMAREA using reflection to learn how you can use PHP to discover all the methods on the Java class.


Linking to the program
$program = new CICSProgram('LIBRARY');
             

First, we create an instance of the built-in class CICSProgram, which represents the CICS program with which we want to interact. The name of the CICS program is specified as the constructor argument, in this case "LIBRARY." If the program were to be renamed, this argument would need to be changed.

Why do I see "com.ibm.cics.server.InvalidProgramIdException: CICS PGMIDERR Condition" instead of the expected output?

Double-check that the argument passed to the CICSProgram constructor represents the name of the COBOL program installed on your CICS system.

$program->link($COMMAREA);

The link method on the CICSProgram class triggers the execution of the CICS program. If a single COMMAREA argument is supplied, as is the case here, it will be used by the CICS program as a container for both input and output data. You may also supply two separate COMMAREA arguments, in which case the first argument will be expected to contain input data, and any output data will be written to the second. It is also possible to supply no arguments, which is useful in cases where the CICS program has no input and output.

try / catch block

If the link fails or the linked program terminates abnormally, the link method will throw a CICSException. The getMessage() method on the exception object reveals details of the failure, including the type of the underlying Java exception. For example, if an invalid program name is specified as the argument to the CICSProgram constructor, the code above would print:

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


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

After link() successfully returns, the COMMAREA contains the output of the invocation. In step 3 of the PHP script above, we use various methods specific to the Library_Commarea class to obtain the total number of books, then to iterate over the list of books, printing the title and author of each one.


Investigating the Commarea using PHP reflection

Setting input data on a COMMAREA before a link and retrieving output data from it afterwards requires knowledge of the setter and getter methods on the COMMAREA class. If you don't have a list of these methods at hand, it is simple to obtain one with PHP reflection.

For example, the following script uses the PHP reflection classes (see Resources) to obtain the list of methods available of the class Library_Commarea:


Listing 4. Using reflection, part 1
<?php
java_import('library.Library_Commarea');
$COMMAREA = new Library_Commarea();
$rc = new ReflectionObject($COMMAREA);
foreach ($rc->getMethods() as $method) {
	echo $method->getName() . '<br/>';
}
?>
             

The output of the script in Listing 4 is:

Library_Commarea
__tostring
setLibItemCount
getLibReturnCode
setLibRequestType
setLibReturnCode
getByteBuffer
getLibRequestType
getLibBookItem
getLibItemCount


Aside from method Library_Commarea() (which is the constructor) and getByteBuffer() (which provides access to the raw byte array holding the COMMAREA data), all the other methods are getters and setters for COMMAREA fields. Those used in the initial script are marked in bold.

Some getters return complex data structures, such as the getLibBookItem() method above, which returns an object representing a book. The same technique can be used on these data structures to discover which fields can be accessed. For example, here we use the PHP function get_class_methods() (see Resources) to establish which fields can be accessed on a book:


Listing 5. Using reflection, part 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));
?>
             

The output of the script in Listing 5 is:

 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
)
             


Troubleshooting the classpath with phpinfo()

If you see warnings or errors suggesting that the COMMAREA class cannot be found, check your Java classpath to ensure it includes a directory or JAR file containing the library directory (which contains the generated classes).

This can be done directly from php code using the PHP function phpinfo():

<?php 
phpinfo();
?>
             

Accessing that script in a browser will display lots of information, including the full classpath:


Figure 1. Checking your Java classpath with phpinfo()
A sample output screen showing various variable settings

classpath.png

More generally, phpinfo() is a useful tool for investigating many aspects of the PHP environment.

3 of 9 | Previous | Next

Comments



static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Web development, Open source
ArticleID=383593
TutorialTitle=Build a RESTful service on CICS with PHP
publish-date=04212009
author1-email=robin_fernandes@uk.ibm.com
author1-email-cc=
author2-email=jlawrence@uk.ibm.com
author2-email-cc=