Writing Java 5 applications for CICS
In this chapter, we discuss the changes that you might want to consider when migrating your Java application to run on Java 5. We also offer some guidance for Java programmers who are relatively new to CICS and z/OS.
5.1 Migrating Java applications to Java 5
Migrating to Java 5 brings opportunities to use new features of the Java language to write more maintainable and better-performing programs and some small potential challenges. In this section, we help you to deal with some of the problems that might be introduced by migration to Java 5, and then we show you how you can benefit from the advantages offered by the new features.
5.2 New compiler errors and warnings
Migrating existing programs to Java 5 can bring some small challenges, even if you do not use the new features. New compiler warnings are not uncommon due to differences in coding syntax brought about by the new language features. While these warnings tend to be harmless, it is useful to know why they are being issued, and it is worth considering updating code to make use of the new features.
In the following sections, we discuss some of the errors and warnings that you are most likely to see, along with their cause and what action is appropriate (if any).
Of course, you can avoid all of the errors and warnings by compiling with the '-source 1.4' flag, but this does rather defeat the point of switching to the newer version of Java.
5.2.1 Error: syntax error on token 'enum'
Error: syntax error on token 'enum'. This occurs when you have code similar to this:
Vector myVector = new Vector();
Enumeration enum = myVector.elements();
The 'enum' is now a keyword in Java, so this error requires a change to the variable name. While you are making that change, consider the user of the Iterator class in preference to Enumeration and even replacing Vector with one of the List implementors, such as ArrayList or LinkedList.
More information about the new keyword 'enum' is in 5.3.4, “Typesafe enums” on page 81.
5.2.2 Warning: ClassX is a raw type. References to generic type ClassX<E> should be parmeterized
This warning is issued for any of the collection classes, such as ArrayList, Map, and so on, where 'ClassX' is replaced by the collection class name. The warning is pointing out that Java 5 introduced an extension to the collection classes that allows the type of object to be stored in the collection to be specified and checked at compile time, rather than at runtime.
This is only a warning and does not stop the code compiling, and the code will still run as it did under Java 1.4 without modifications, but much can be gained in terms of code readability, maintenance, reduction in errors, and even performance by making use of this new feature. For more information, review 5.3.1, “Generics” on page 77.
5.2.3 Removed Error for boxing/unboxing
Prior to Java 5, if you tried to use a primitive value where you should use an Object, and vice-versa, then you received an error. Java 5 introduced automatic boxing and unboxing, which automatically converts between primitives and their wrapper classes. Although this avoids compiler errors and simplifies code, it does not remove the runtime overhead of these conversions. Take care to use the appropriate type, for example, objects where the value must be stored in a collection class, and primitives where the value is to be used in a calculation or a boolean operation. For more details, see the section 5.3.3, “Autoboxing and unboxing” on page 80.
5.3 Using the new features in Java 5
After you are running Java 5, you benefit by using the new features that Java 5 offers.
For a complete description of the new features, see the Java 5 documentation. Highlights of the new features include:
Generics
Typesafe enums
Enhanced for loop
Autoboxing & unboxing
Keep in mind when considering to use these new features that they do not run on older versions of Java. Any code that you write to use these features only runs on Java 5 or later. Therefore, wait until you migrate your Java runtimes to Java 5 before updating your code to exploit these new features.
5.3.1 Generics
Java has provided a rich set of collection classes since Java 2. These collection classes provide efficient ways to manage large and small collections of objects efficiently, and are the preferred way to handle collections of objects, since their introduction. They also had one significant shortcoming: There was no way to specify the type of object being stored in the collection. All objects were stored as instances of Object, and had to be cast into their actual type when they were extracted from the collection, which resulted in messy code with casts when ever objects were extracted from the collection. Worst still, as any type of object could be added to the collection, it was sometimes necessary to test the type of object before the cast was performed or risk runtime exceptions when a cast was attempted into the wrong class.
Java generics provide a simple solution to these problems by offering type-safe versions of the collection classes.
Let us start with a simple piece of example code written without the use of generics. This simple piece of code in Example 5-1 counts the number of uses of the word 'CICS' in the passed collection.
Example 5-1  
public static int countCICS(Collection c) {
int count = 0;
Iterator iterator = c.iterator();
while (iterator.hasNext()) {
if (((String) iterator.next()).equals("CICS"))
count++;
}
return count;
}
With this code we would want to state in the documentation of the method that the passed collection only contains instances of the String class and hope that who ever uses this method reads the comment and obeys it.
Example 5-2 is a simple piece of code that invokes that method.
Example 5-2  
public static void testCountCICS() {
List al = new ArrayList();
al.add("Hello");
al.add("CICS");
al.add("Programmer");
al.add(new Integer(4)); // (1)
 
int count = countCICS(al);
}
While the code in Example 5-2 compiles without errors, when we try to run the program we get a ClassCastException because of the addition of an Integer object at line (1) when the countCICS() method attempts to cast this Integer into a String.
We also have the same methods implemented using generics. Example 5-3 is the updated version of countCICS().
Example 5-3  
public static int countCICS(Collection<String> c) {
int count = 0;
Iterator<String> iterator = c.iterator();
while (iterator.hasNext()) {
if (iterator.next().equals("CICS"))
count++;
}
return count;
}
The changed code is highlighted. The addition of ‘<String>’ to the declaration of the Collection and Iterator state that these only hold String objects. Because the Iterator declared that it only handles String objects, there is no longer a need for a cast when the values are read from the iterator in the ‘if’ statement.
The code '<Type>' can be read as 'of Type'.
Example 5-4 is an updated version of the test code, but this time using generics when we create the collection to be processed.
Example 5-4  
public static void testCountCICS() {
List<String> al = new ArrayList<String>();
al.add("Hello");
al.add("CICS");
al.add("Programmer");
al.add(new Integer(4)); // (1)
 
int count = countCICS(al);
}
Once again, the changed code is highlighted. The declaration of the List and the creation of the ArrayList also have ‘<String> appended to them to state that they only accept String objects.
This code will fail with a compile error on the line labeled (1) where it tries to add the Integer to the collection. With the use of generics, the compiler enforces the requirement for the collection to only contain Strings, which reduces the risk of errors at runtime. Removing or correcting this line removes the compile time error, and we can then have confidence that the code does not fail at runtime. If the code compiles without warnings, then we know that we will not have a ClassCastException at runtime. We also have the benefit of simpler code without the cast and less parentheses in the 'if' statement.
Generics are compatible with the existing collection classes, which allows easier migration of existing code. So, we can invoke the new version of countCICS() (Example 5-3 on page 78) with the old version of the test code (Example 5-2 on page 78). Of course, this still gives us a runtime error because of the attempted cast of the Integer object into a String. After this problem is resolved we still have a warning message telling us that the conversion from old (un-typed) collection to a new (typed) collection cannot be guaranteed to be type safe because we do not know at compile time whether the collection only contains objects of the correct type.
Correspondingly, the new test method (Example 5-4 on page 78) can be used to invoke the old countCICS() method (Example 5-1 on page 77). After the invalid line at (1) is corrected or removed, this code compiles and runs without errors.
Programmers who are familiar with C++ might notice that the syntax of Java generics is similar to C++ templates, but note that while they might look similar, the implementation is very different and the two should not be confused.
5.3.2 Enhanced for loop
Java offers the typical for loop construct where of the form
for (initialiser; exit condition; incrementor)
With Java 5, the 'For-Each' loop is introduced, which has syntax of the form:
for (element : collection)
The colon (:) can be read as 'in'. This version of the for loop can be thought of as ‘for each item in the collection’. The syntax, and its advantages, are probably better demonstrated using an example, Example 5-5, such another re-work of the countCICS() method as used in the previous examples.
Example 5-5  
public static int countCICS(Collection<String> c) {
int count = 0;
for (String s: c) {
if (s.equals("CICS"))
count++;
}
return count;
}
Example 5-5 on page 79 also demonstrates the new form of the 'for' loop. The complexity of the code is reduced further. When compiled, the code gains an implicit Iterator, but this is hidden from the programmer, which results in simple and easy-to-read code.
There are limitations to this code, for example, if we wanted to do more than merely count the instances of the word 'CICS', such as remove all instances of the word 'CICS', then we want to invoke the remove() method on the Iterator. Because we do not have access to the Iterator, we cannot do this, and so this version of the for loop is not appropriate.
There is not much to be gained from replacing existing code with the new for loop syntax, but it is a useful construct to consider using in new code.
This code also demonstrates the questionable practice of using single character variable names, which of course is not recommended in production code.
5.3.3 Autoboxing and unboxing
Because the Java collection classes only hold Objects and not primitives, it is sometimes necessary to 'box' primitives in their appropriate wrapper class to store them in a collection and then 'unbox' them to get the primitive value back when the object is read from the collection. Although this code might be trivial to write, it does add clutter to the code.
A slightly contrived example of boxing and unboxing might be something like the code that creates an array of Strings, calls a method that returns the passed Strings mapped to the length of each String, and then reports on the lengths of the Strings, as shown in Example 5-6. The first version of the code uses explicit boxing and unboxing.
Example 5-6  
public static void testStringLengths() {
String[] strings = new String[] {"Hello", "CICS", "Programmer"};
Map<String, Integer> result = getStringLengths(strings);
for (Map.Entry<String, Integer> e: result.entrySet())
System.out.println("String " + e.getKey() + " length is " + e.getValue().intValue());
}
 
public static Map<String, Integer> getStringLengths(String[] strings) {
Map<String, Integer> map = new HashMap<String, Integer>();
for (String s : strings) {
map.put(s, new Integer(s.length()));
}
return map;
}
The code also provides another demonstration of the use of generics and the enhanced for loop.
Now, the same code with automatic boxing and unboxing looks like Example 5-7 on page 81.
Example 5-7  
public static void testStringLengths() {
String[] strings = new String[] {"Hello", "CICS", "Programmer"};
Map<String, Integer> result = getStringLengths(strings);
for (Map.Entry<String, Integer> e: result.entrySet())
System.out.println("String " + e.getKey() + " length is " + e.getValue());
}
 
public static Map<String, Integer> getStringLengths(String[] strings) {
Map<String, Integer> map = new HashMap<String, Integer>();
for (String s : strings) {
map.put(s, s.length());
}
return map;
}
The changed lines are in bold text.
Boxing and unboxing, whether automatic or manual, has a performance overhead. Boxing creates a new object, which not only takes some processing, it also results in another object (the wrapper instance) on the heap that must be garbage collected at some time. Unboxing requires a method call to read the primitive value from the wrapper class. Because of this, only use the boxing and the wrapper classes when they are required to avoid unnecessary performance impacts. As the introduction of automatic boxing and unboxing hides the process, take additional care to avoid unnecessary conversion and the associated impact on performance.
5.3.4 Typesafe enums
A common approach to enumerated values in Java is to use static int values like Example 5-8.
Example 5-8  
public static final int CONNECTION_OPEN = 0;
public static final int CONNECTION_CLOSING = 1;
public static final int CONNECTION_CLOSED = 2;
 
public static final int SECURITY_SSL = 0;
public static final int SECURITY_NO_SSL = 1;
 
public void createConnection(int initialState, int securitySetting) { ...}
 
public void someMethod() {
createConnection(OPEN, NO_SSL) // (1)
createConnection(NO_SSL, OPEN) // (2)
}
Although the code in Example 5-8 will compile, it has many problems, which include:
It is not typesafe: While lines (1) and (2) both compile, one of them has unexpected results.
Trace values are unhelpful: Seeing the int values in the trace tells you very little without reading the program source code.
The variable names must include their context because there is no namespace that is associated with the int variables.
It is brittle: If a new value is added in the middle of the values or the numbering is changed, any code using the values must be re-compiled.
It is possible to write code that addresses these issues, such as Example 5-9.
Example 5-9  
public class ConnectionStatus {
public static final ConnectionStatus OPEN = new ConnectionStatus("Open", 1);
public static final ConnectionStatus CLOSING = new ConnectionStatus("Closing", 2);
public static final ConnectionStatus CLOSED = new ConnectionStatus("Closed", 3);
 
private final int value;
private final String description;
 
private ConnectionStatus(String description, int value) {
this.description=description;
this.value = value;
}
 
public int getValue() {return value; }
public String getDescription() {return description; }
public String toString() { return description + ":" + value; }
}
 
public class Security {
public static final Security SSL = new Security("SSL", 1);
public static final Security NO_SSL = new Security("No SSL", 2);
private final int value;
private final String description;
 
private Security(String description, int value) {
this.description=description;
this.value = value;
}
public int getValue() {return value; }
public String getDescription() {return description; }
public String toString() { return description + ":" + value; }
}
 
public void createConnection(ConnectionStatus initialState, Security securitySetting) {...}
 
public void someMethod() {
createConnection(ConnectionStatus.OPEN, Security.NO_SSL);
}
Example 5-9 on page 82 addresses the issues, but it is verbose. We do have the benefit that if the initialState and securitySetting parameters are reversed, we get a compile error that is easy to fix.
With the introduction of the 'enum' keyword, we can have the advantages of the dedicated class, but without so much typing. Example 5-9 on page 82 can be coded in a smaller form, as shown in Example 5-10.
Example 5-10  
public enum ConnectionStatus {OPEN, CLOSING, CLOSED};
public enum Security {SSL, NO_SSL};
 
public void createConnection(ConnectionStatus initialState, Security securitySetting) {...}
 
public void someMethod() {
createConnection(ConnectionStatus.OPEN, Security.NO_SSL);
}
The enum values can also be used as a type for generics and even can be used in the enhanced for loop in a line, such as:
for (ConnectionStatus state : ConnectionStatus.values()) { ... }
There are other advantages to the new enum types, including the ability to add enum values without breaking existing code, extensions to the Java Collections classes, and add methods or interface implementations to an enum.
5.4 Introduction to CICS for Java programmers
There are differences between writing Java programs for CICS and writing Java programs for other environments. In this section, we briefly discuss some of these issues, but this is not intended to be a complete description of CICS. For a complete description, review the CICS Transaction Server documentation.
CICS is a transaction processing system, which means that it provides services for a user to run applications online at the same time as many other users are submitting requests to run the same or other applications, using the same files and programs. CICS manages the sharing of resources, integrity of data, and prioritization of execution, while maintaining fast response times.
A CICS application is a collection of related programs that together perform a business operation, such as processing a product order or preparing a company payroll. CICS applications execute under CICS control using CICS services and interfaces to access programs and files.
You can write CICS application programs in a variety of languages, including COBOL, Assembler, C, C++, PL/I, and of course, Java. Most of these languages access CICS services through the 'EXEC CICS' interface. Java, however, does not use the EXEC CICS interface and must use the JCICS classes to access CICS services.
CICS provides a selection of services to the application program. For a thorough overview of these services, refer to the CICS Transaction Server documentation; however, here we do provide a summary of some of the key features that are provided to Java programs:
Data management services:
 – CICS provides the ability to access VSAM files with data backout or forward recovery in the event of failures.
 – CICS supports access to databases, such as DB2 through appropriate APIs.
 – CICS also provides two proprietary file structures: Temporary Storage (TS) and Transient Data(TD).
Communication Services:
 – CICS provides access to a variety of display devices over SNA and TCP/IP protocols.
 – CICS supports communication inbound and outbound over IIOP using an Object Request broker (ORB).
 – CICS also provides a selection of proprietary protocols that allow programs to access programs and other resources in other regions and asynchronously start transactions in the same or other CICS regions.
 – Requests to run programs that are defined in other CICS regions can be automatically routed to the other region with the results being routed automatically back to the calling region.
Unit of work services:
 – CICS supports ACID transactions and gives programs the ability to programmatically commit or rollback transactions.
These features are available to Java programs through the JCICS classes, which we discuss in 6.1, “Introduction to JCICS” on page 90. There are also other services that are provided in CICS that are not exposed to CICS Java programs.
5.5 CICS program design guidelines
Designs for programs that run in CICS, or in other multi-user environments, can be different to designing programs that run in single-user environments. The issues and guidance for designing such applications are worthy of a book in themselves and are outside the scope of this book; however, some basic principles are worth stating here for you to keep in mind when you design and write CICS Java programs to help you along the road to writing efficient and well-behaved Java programs for CICS:
CICS systems handle multiple transactions and multiple users simultaneously.
CICS applications frequently are distributed across multiple CICS regions with the work frequently being routed dynamically to a system with available resources.
CICS programs typically must be highly scalable, which means that resources must be shared between multiple programs and often multiple instances of the same program, often in different CICS regions.
The program must be written in such a way as to avoid multiple users updating the same record at the same time, which CICS services offer help with.
The program must be designed to have a clean approach to error handling:
 – It is essential that when an error occurs, sufficient information is provided to allow successful debugging of the program. Empty ‘catch’ blocks fail to do this and endear their author to the programmer attempting to debug the problem.
 – Any resources that the program holds must be released both when the program ends normally and in the case of an error.
Programs must be designed to not make excessive demands on system resources, such as processor time, memory, communication with auxiliary storage, and communication bandwidth. Java programmers should pay particular attention to avoid creating excessive and unnecessary objects on the heap.
Ensure that private data from one program invocation is not available to other invocations of programs, which requires particular care when writing Java programs that are executed in a continuous JVM.
CICS programs typically exist and are modified over a long period of time. Programs must be written in such a way to be easily maintained and modified by other programmers in the future.
Because of these issues, Java programmers must take care to write well-behaved Java applications. Programs that hog resources, perform badly, or create large numbers of unnecessary objects in the Java heap can severely impact the performance of the CICS systems. Even a properly configured and carefully turned set of CICS regions will not perform well if the application is badly written.
5.6 Differences in Java with CICS
A CICS Java program should be written to work through CICS when accessing system resources to ensure that CICS can manage those resources effectively and ensure that they are shared between all of the programs that are running in the system. CICS JVMs are typically re-used, so take care to not leave resources 'lying around' between uses of the JVM because this impacts transaction isolation and can impact performance and resource usage.
Because of this, there are certain Java language features and APIs that should not be used by Java applications that are running in CICS, and others should be used with care.
Java resources that should either not be used or that only should be used with caution are discussed in the next sections and alternatives are suggested where appropriate.
There are also third-party APIs, drivers, and extensions that can be used in Java programs. Many of these can be used in Java in CICS, but be aware that they typically do not benefit from CICS services, such as transaction support.
5.6.1 Threads
Java programs can and often do start new threads, but avoid this when the Java programs are running in CICS. Only the thread that invoked the public static main method (the initial program thread - IPT) has access to CICS resources, Additionally, any thread that the IPT starts is not automatically destroyed when the IPT terminates, which damages isolation of the transaction running in the JVM and has the potential to waste system resources.
Because CICS provides the ability for large numbers of programs to run simultaneously and manages access to resources and communication between the programs, it typically should not be necessary for a Java program in CICS to start new threads.
5.6.2 Sockets
Sockets that are created using the classes in package java.net use the socket support of the JVM. CICS cannot transactionally manage these sockets, and if they are created by threads that the Java program creates, they can outlive the program that created them and compromise the isolation of the transaction running in the JVM, which has the potential to waste system resources.
CICS system programmers are encouraged to use the Java 2 security policy to stop the creation of the Java sockets, so any program that is written to use these sockets might not run in a production system.
JCICS provides support for TCP/IP. HTTP and web services through CICS.
5.6.3 File I/O
The JCICS API provides access to VSAM files through CICS services and should be used in preference to the java.io.File class and related classes. If access is required to a PDS, the JZOS libraries should provide a suitable API.
Modifications to hfs, zFS(files), or PDS members cannot be backed out by CICS if the transaction is rolled back, so take care if you apply updates to these files.
5.6.4 Static data
Static storage is not re-initialized for each invocation of the program in a continuous JVM. So take special care with static fields in Java programs for CICS. This can be both a blessing, and a challenge.
Data that is likely to be needed repeatedly in the JVM can be initialized in the static values and re-used by future invocations of the program in that JVM. Do not assume that the static values were already set because the different invocations of a program might run on different JVMs, and other programs might also run in the same JVM. This re-use of static value can, when used properly, improve program performance.
Do not store data that must not be shared between invocations of a program, such as customer account numbers, in static fields, or the fields should be initialized before the program terminates; otherwise, transaction isolation is impacted.
The CICS Java documentation offers the following guidelines:
Define a class field as private and final, whenever possible. Be aware that a native method can write to a final class field, and a non-private method can obtain the object referenced by the class field and can change the state of the object or array.
Be aware of system-loaded classes that use changeable class fields.
The 'CICS JVM Application Isolation Utility' tool that is provided with CICS can help you to check your usage of static fields and classes. We describe this tool in 2.4, “Analyzing programs for use in a continuous JVM” on page 23.
Further information is in the CICS Java documentation.
5.6.5 Modifying the JVM state
Although it is occasionally desirable to modify the state of the JVM, such as, changing the default time zone, programs must restore the value to its original setting before the program completes so that the changes do not affect programs that run subsequently in the JVM.
5.6.6 Releasing resources at the end of program execution
It is essential to ensure that resources that a program uses are released at the end of the program, whether the program ends normally or in an error condition. Failure to do so can waste system resources, cause problems with resources being locked out from other programs, and in the example of DB2 connections, stop a new connection being opened by subsequent programs that are running in the JVM due to the existence of a connection that was already opened and not closed by a previous program.
5.6.7 Object Request Broker (ORB)
Java programs in CICS that use the Object Request Broker (ORB) use the CICS ORB. This ORB implementation uses CICS services. For details of support provided by this ORB, see the CICS documentation.
5.7 Data type conversion
CICS runs on System z machines and uses the Extended Binary Coded Decimal Interchange Code (EBCDIC) character set, rather than ASCII, which is the case with many other machines. While Java programs use unicode for its internal representation of characters and strings, conversion to and from the native character set of the host machine is often required. Do not assume that the host machine's character set is ASCII or unexpected errors will occur.
5.7.1 ASCII & EBCDIC issues
There are several common problems with code page conversions in Java and other languages when working across platforms. Java provides help with many of these problems, and you can avoid them with careful coding.
One common problem is assumptions about the line separator character. It is common to write code that expresses the line separator character as ' '. This only works on some platforms and is a common cause of problems. Even using the println(...) method can be a problem. To avoid problems with line separators, it is safest to use code that works on all platforms, such as:
String lineBreak = System.getProperty("line.separator");
out.print("Line of text.");
out.print(lineBreak);
When you read or write text, you typically want to use the default encoding of the platform that is running the code, such as, EBCDIC when running in CICS, but if the text came from or is being sent to another platform, a different encoding might be required.
XML can offer particular problems. XML documents are normally stored as text, but they store the encoding name within them. So an XML document might begin:
<?xml version="1.0"? encoding="UTF-8">
An XML document from another platform is typically transferred to the host machine that is running the CICS region as a text file, so the text that makes up the contents of the file is converted into EBCDIC, and this of course conflicts with the encoding, as specified in the header. Alternatively, the file can be transferred in binary mode, in which case the encoding tag is correct, but the file is difficult to read as a text file because it is not encoded in EBCDIC. Similar problems exist with XML that is generated on the host and transferred to a non-EBCDIC machine.
5.7.2 Conversion to and from COBOL, PL/I, and Assembler data types
It is often necessary for CICS Java programs to interact with existing COBOL, PL/I, or assembler programs in CICS. These languages support data types that do not exist natively in Java, such as packed decimal and zoned decimal numbers.
Usefully, this conversion is discussed in the existing IBM Redbooks publication Java Stand-alone Applications on z/OS Volume 1, SG24-7177, and code is provided in the additional material with that book that carries out these conversions. In these cases, it is necessary to specify the code page to be used in the conversion. Java provides the ability to do this and the character set for conversions can be specified on classes such as InputStreamReader and OutputStreamWriter in the 'java.io' package.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset