S8360: Java: OO Concepts & Java for COBOL Programmers.
SHARE Technical Conference
August 2002


Abstract:

A classic Report Writer application (read file, sort, report) will be used as an example for the COBOL programmer to illustrate Object Oriented programming in Java. The speaker will start with a working COBOL report program, then show a Java implementation that produces equivalent results.

The author has been writing programs since 1965 in Fortran, COBOL, PL/1, Algol, Pascal, C, C++, and various assembly languages. He has been exploring Java since 1996.



Steve Ryder, Senior Director
JSR Systems (SHARE Code: JSR)
2805 Robbs Run
Austin, Texas 78703

sryder@jsrsys.com
www.jsrsys.com
512.917.0823


Clients for whom the speaker has developed code include:
The University of Texas at Austin 1965-1966
Texas Education Agency 1966-2000
Houston Ind. School District 1975-1981
Conroe Ind. School District 1980-1993
United States Navy 1966-1994
Capitol Appraisal Group, Inc. 1981-...

Return to JSR Systems Services.
Return to JSR Systems' home page.
Copyright © 2002, JSR Systems, All rights reserved.




Navigation hints:
  • Clicking on SHARE logo will go back one "page".
  • Clicking on SHARE moto will go forwared one "page".
  • Clicking anywhere else on page will go to "next page".

    Table of Contents
    Introduction

    All the programs/classes used to implement the sample Extract/Sort/Report project are included in the SHARE procedings. However they are not in the handout. These handout and the program examples are available on my web site, www.jsrsys.com.

    I will include code snippets in my discussion of various features of Java so you won't have to flip the appendix. I failed to do this on my last presentation of Java SWING, and lost y'alls attention while you were trying to find the code. I hope this method works better, and will kill fewer trees.

    Your are welcome to use any of the code examples in your own Java applications.












    COBOL:COBOL Concept Description
    Java:Java/OO Similar Concept
    ++:What Java/OO adds to Concept
    When I began Java, I used to think the OO (Object Orientation) was "just like" good programming practices, except it was more formal, and the compiler enforced certain restrictions.

    I no longer think that way. However, when you are beginning I think certain "is similar to" examples will help you grasp the concepts.



    COBOL:Load Module/Program
    Java:Class
    COBOL:PERFORM
    Java:method
    ++:can pass parameters to method, more like FUNCTION
    other programs/classes can call methods in different classes if declared public. public/private gives designer much control over what other classes can see inside a class.


    COBOL:Working Storage, statically linked sub-routine
    Java:instance variables
    ++:(see next)


    COBOL:Working Storge, dynamically loaded sub-routine
    Java:Class variables
    ++:Java can mix both Class variables (called static, just the reverse of our COBOL example, and instance variables (the default).
    Class variables (static) occur only once per Class (really in one JVM run-time environment).
    Instance variables are unique to each instance of a class.
    Here is an example from class JsrSysout. From my COBOL background I like to debug my code by DISPLAYing significant data to the SYSOUT data set. There is a Java method for this, System.out.prinln(...). The problem with this method is that the data you want just scrolls off the Java console, the equivalent of SYSOUT or perhaps DISPLAY UPON CONSOLE if you had your own stand-alone machine. I needed a way to easily do displays that would stop when the screen was full. Since there is only one Java console, the line-count for the screen clearly needs to be a class variable, so all instances (each program/class that logs here has its own instance of JsrSysout) stop at the bottom of the screen.





      static final String COPYRIGHT = 
      "Copyright 1998-2000, JSR Systems.  See: www.Jsrsys.com/copyright.";
    
      static final int MAXLINELEN = 80;
      static final int MAXSCREEN  = 21;
      static int qBig = ' ';  //  81 "Q" to terminate all instances 
                              //  82 "R" run, do not query user any more
      int       qChar = ' ';  // 113 "q" to terminate this instance
      static int nLines = 0;
      static String   syslogFileName = "";
      // make syslog... static so any program can turn on logging of ALL calls 
      static JsrLineOut syslogFile = new JsrLineOut("NoLog");
    
    The above illustrates the use of class vs. instance variables. static final is a special case. This means the code is a constant, and can not be modified. Since it is a constant, making it static (a class variable) only makes sense. nLines (the line-count) is also static, as is the syslogFileName. JsrSysout has a nice feature that lets any program/class calling it turn on a permanent copy of what has been displayed via JsrSysout. This can be a useful audit trail for production programs, as well as a way to see what happened if a dump clears the screen. qBig is updated if the user enters a capital Q (or R) in response to a screen full message. If Q is entered, the program runs, but with no displays. If R is entered the program continues to run but does not stop when the screen is full. This is useful for a long running program that might terminate. qChar is updated if a lower-case q is entered. This terminates output from only this instance of JsrSysout.

    Here is the code that implements the DISPLAY function.
      void display(String displayString)
      {  
         if (qChar != 113 && qBig != 81) // !=q   != Q
         {
            // System.out.println("Last q="+qChar+", Last Q="+qBig);
            nLines += (displayString.length()+MAXLINELEN)/MAXLINELEN;
            if (nLines > MAXSCREEN)
               getQ(displayString);
            else   
            System.out.println(displayString);
            if (syslogFileName.length() > 0)
            {
                syslogFile.setLine(displayString);
            }
         }
         return;
      } 
    
    Other methods implented in JsrSysout are accept, speedometer, setNoStop, and syslog.
    accept is obvious. speedometer is a way to display without scrolling the screen. setNoStop sets qBig to R, in effect letting a program prevent scrolling. sysout causes all the displays to be logged to a disk file.

    Multiple Instances of same class:
    One (calling program) class can create multiple instances of the same class. Why would you want to do this? One good COBOL example is I/O routines. In COBOL you would need to code one I/O routine for each file you wish to access. If you want to open a particular file twice in one run-time environment you would need a different I/O routine with a different name, even if the logic was identical.

    With Java you could code just one class for a particular logical file type. Then for each file you wish to read (or write) you simply create another instance of that class using the new operator. Here are some snippets of code from program IbfExtract that do exactly that. This program exploits the fact that I have written a class for Line Input, and another class for Line Output. These are called JsrLineIn and JsrLineOut.
      String      inputLine = " ";
      JsrLineIn   input   = new JsrLineIn();
      JsrLineOut[] output   = new JsrLineOut[MAXOUT];
      String[]     outName  = new String[MAXOUT];
    
    This program is going to read from one input file, but will create an undetermined number of output files, based on the contents of the input file.
          input.setName(parm[0]);
          while (0 <= (recNum=input.getNext())) 
          {
             inputLine = input.getLine();
             fileName  = inputLine.substring(0,10).trim();
             if (fileName.equals("RP5226")) fileName += "."+inputLine.substring(17,21);
             for (i = 0; i < iMax && !fileName.equals(outName[i]); i++) {}
             /** alternate: could do Hashtable if had large # of files...
             //sysout.display("*"+fileName+i+"*");
             if (i == iMax)
             {
                iMax++;
                output[i]  = new JsrLineOut();
                outName[i] = fileName;
                output[i].setName(fileName);
                sysout.display("*"+fileName+"["+i+"]");
             }
             line100++;
             if (line100 == 100) /** alternate: if (recNum%100 == 0)  <--!!!
             {
                line100 = 0;
                sysout.speedometer("Copying record: "+recNum);
             }
             output[i].setLine(inputLine);
          }
    
    The setName method of class JsrLineIn opens an input file for that name. It then begins a very typical loop. The getNext method for input positions the file to the next record, and returns the record number. The getLine method returns the current input record (line). If the input columns 1,10 == RP5226, the program constructs an output fileName of RP5226+columns(18,21). It then checks to see if this file is already open (searching the table of file names). If it is not, the new file name is stored in the table, and a new instance of JsrLineOut is created in the array called output.

    This illustrates another dynamic feature of Java. When output is first created, it is an array of null pointers, it takes very little space. Only when a new object is created, and the pointer to it implicitly put in the array does storage for the object get allocated. That object can be anything from a String to an very complex Class.

    The setLine method of JsrLineOut writes one record (line) to the output file opened by that instance of JsrLineOut. The speedometer method of JsrSysout writes a line to the system console with no line feed. This is a convenient (non GUI) method of monitoring the programs progress.

    COBOL:PICTURE
    Java:No real equivalent.
    I therefore invented a method to mymic a ZZZ,ZZZ,... mask for integer input. I have generally grouped my utility functions in JsrUtil. These are methods that really don't related to any type of object. Here is an example of padLeft that implements this logic. padLeft is also a good example of polymorphism. In COBOL, if you have different parameter lists you need different entry points. In Java, the types of parameters are part of the definition. For example:
     * paddedString  = u.padLeft(oldString,10);  // pad left with blanks
     * paddedString  = u.padLeft(oldInt,10);     // comma inserted every 3 bytes.
     * paddedString  = u.padLeft(oldInt,10,2);   //   " + .00 (2 is # decimal points).
     * paddedString  = u.padLeft(oldLong,10);     // comma inserted every 3 bytes.
     * paddedString  = u.padLeft(oldLong,10,2);   //   " + .00 (2 is # decimal points).
    
    All the padLeft methods do essentially the same function. However, the ones that accept int or long values, will also insert the comma in every 3 bytes, and suppress leading zeroes. The number of decimal digits is my way of handling the issue of decimal rounding. This will work as long as you add or subtract integers with the same assumed decimal precision, and, if you multiply or divide, you manually handle the scaling.

    COBOL:Decimal arithmetic
    Java:Not in native Java, but IBM has implemented some BigDecimal classes.
    I consider this the major weakness of Java for accounting type applications. I would have liked to see the packed decimal data type as part of the native JVM byte architecture. I guess it is not there because it is not in C or C++. I have only read about the BigDecimal classes. Based on session 0018 from March 2002 SHARE: "Decimal Arithmetic: e-10 for e-Business", one pays a significant performance penalty by using BigDecimal. However, I am not convinced that this is a significant factor in a typical I/O bound application. BigDecimal is now part of standard Java.

    COBOL:COPY or INCLUDE
    Java:Inheritance
    ++:Much more powerfull!
    In COBOL, if you change a COPY or INCLUDE member, you must recompile all the programs that use it. In Java, if program B inherits from program A, a change in program A is automatically inherited by program B without recompiling! Yes, this really works, and lends great power to Java applications. I exploited this for my Read/Sort/Report system. Class IbfReport contains all the basic logic common to the report programs. It has appropriate defaults for all of its methods. Classes IbfRP#### extend IbfReport, and contain only those methods unique to a particular report. If a change is made in IbfReport, it is reflected in the IbfRP#### programs (classes) the next time they are run.

    COBOL:ON EXCEPTION
    Java:try/throw/catch
    ++:can limit scope of error detection (see following)


    COBOL:OPEN
    Java:Input Streams
    ++:Automatic error detection, both a blessing and a curse.
         BufferedWriter              outFile;
         try {outFile = new BufferedWriter(new OutputStreamWriter
                                          (new FileOutputStream (fileName)),1000000); 
             } catch ( IOException  eIO )
                     {System.out.println("I/OError! "   + fileName); 
                      recNum=-1; 
                     } 
         return recNum;
    
    The first really useful Java classes I wrote were JsrLineIn and JsrLineOut. These two classes are the heart of any Java programs/classes I have written (right up there with JsrSysout). And this try/catch stuff was what forced me into it. My first programs (copied from the Java in 21 days book) had try {} wrapped around all the code, and placement of the catch was difficult. I realized that I needed to encapsulate the read logic and the error detection code. If there is an error, I log the error, and return -1.

    COBOL:WRITE
    Java:write (yes, really).
      int setLine(String parmLine)
      {
         if (recNum >= 0) /** alternate: if (null !=outFile) <--much better
         {
           if (fileName.equals("")) fileName = lastName; //2000-07-28
           try { outFile.write(parmLine);
                 outFile.newLine();  // platform dependent line separator
                 if (flushOn) outFile.flush(); // flush after each line...
               } catch ( IOException  eIO )
                       {System.out.println("I/OError! "   + fileName); }
         }
         recNum++;
         return recNum;
      }
    
    This is the method to actually write a line of output. It only does the write if the open was successful. JsrLineIn is a good example of the benefit of run time binding in Java. When I wrote the first versions, Buffered streams were not implemented. Java wrote a character at a time. This was not an issue for local file systems, but it made Java so slow on networks as to be unusable. When Buffered streams became available, all I had to do was modify two classes, and all my programs started running very fast over the network! However, a downside of that is that if the program abended, I often had no output, because the buffer size I choose was very large. Thus I implmented the setFush method which sets the boolean variable flushOn to true or false (default is false). If it is on, I flush the buffer after each line, which is still much faster than a character at a time. setLine returns the # of the line written, which can be displayed by speedometer, and is logged when the file is closed.

    COBOL:CLOSE
    Java:close method
      int close()   
      {  
         if (recNum > 0) /** alternate: if (null !=outFile) <--much better
         {
           if (displayOn)    
               sysout.display("Close Output: " + u.padLeft(recNum,10)
                            + " Records: "+ fileName  
                            +"                          ");   
           try {outFile.close();  // free up resource  
               }catch ( IOException  eIO )
                      {System.out.println("I/OError! "   + fileName); }
         }
         recNum   = - recNum;
         lastName = fileName; // save lastName if call w/o setName()
         fileName = "";
         return recNum;
      }
    
    Yup, it is actually called close! All the rest of the code just illustrates my logging logic, and sets up the return to return minus (-) the number of records written. The (-) is just my convention for a closed file.

    COBOL:READ
    Java:read...
      int getNext()
      {
         if (fileName.equals(""))
         {
            sysout.display("JsrLineIn--must use setName([name of File])!!!");
            sysout.display("JsrLineIn--before reading w/ getNext()!!!!!!!!");
            return -1;
         }
    
         if (recNum >= 0)  /** alternate: if (null !=outFile) <--much better
         {
           try {fileLine = inFile.readLine();
               } 
                 catch ( IOException  eIO )
                       {sysout.display("I/OError! "   + fileName); }
           if (fileLine == null)
              return close();
           else
              recNum++;
         }
    
         // sysout.display ("recNum="+recNum+ "Rec="+ fileLine);
         return recNum;
      }
    
      String getLine() 
      {
        return fileLine;
      }
    
    All I have had occasion to use is readLine. There are other read methods in Java, such as readChar.

    Now for the project that is my sample:
    COBOL:Input large file, multiple records types.
    Output, file for each record type (but one type had many buying groups).
    Several report programs, each reads file of its type records, sorts selected records,
    produces report to OUTPUT file.
    One file read many times, once per buying group.
    Java:Expanded functionality of output by writing each buying group to its own file.
    Thus each buying group reads only records for that group.
    ++:Used inheritance to really simplify coding of separate report programs.


    Sample of input:
    RP5196COST0140074001172METHYLENE BLU 1% SDV 10X10ML   0517-0310-10  EA00081400010175AMER REGEN                                  
    RP5226    0024074G051001172METHYLENE BLU 1% SDV 10X10ML   0517-0310-10  EA00101750008140   AMER REGEN                           
    RP5226    0020074G150001172METHYLENE BLU 1% SDV 10X10ML   0517-0310-10  EA00101750003190 * AMER REGEN                           
    RP5226    0001074G231001172METHYLENE BLU 1% SDV 10X10ML   0517-0310-10  EA00101750008140   AMER REGEN                           
    RP5226    0016074G619001172METHYLENE BLU 1% SDV 10X10ML   0517-0310-10  EA00101750008140   AMER REGEN                           
    RP5226    0098074G748001172METHYLENE BLU 1% SDV 10X10ML   0517-0310-10  EA00101750008140   AMER REGEN                           
    RP5226    0022074G840001172METHYLENE BLU 1% SDV 10X10ML   0517-0310-10  EA00101750004350 * AMER REGEN                           
    RP5226    0040074G848001172METHYLENE BLU 1% SDV 10X10ML   0517-0310-10  EA00101750003330 * AMER REGEN                           
    RP5226    0002074G850001172METHYLENE BLU 1% SDV 10X10ML   0517-0310-10  EA00101750008140   AMER REGEN                           
    RP5226    0003074G955001172METHYLENE BLU 1% SDV 10X10ML   0517-0310-10  EA00101750008140   AMER REGEN                           
    RP5196COST0140074001180FLOXIN 400MG TAB 100           0062-1542-01  EA00432510051901J-O-M PHAR                                  
    RP5226    0024074G051001180FLOXIN 400MG TAB 100           0062-1542-01  EA00519010042386 * J-O-M PHAR                           
    RP5226    0020074G150001180FLOXIN 400MG TAB 100           0062-1542-01  EA00519010042386 * J-O-M PHAR                           
    RP5226    0001074G231001180FLOXIN 400MG TAB 100           0062-1542-01  EA00519010043251   J-O-M PHAR                           
    RP5226    0016074G619001180FLOXIN 400MG TAB 100           0062-1542-01  EA00519010043251   J-O-M PHAR                           
    RP5226    0098074G748001180FLOXIN 400MG TAB 100           0062-1542-01  EA00519010043251   J-O-M PHAR                           
    RP5226    0022074G840001180FLOXIN 400MG TAB 100           0062-1542-01  EA00519010043251   J-O-M PHAR                           
    RP5226    0040074G848001180FLOXIN 400MG TAB 100           0062-1542-01  EA00519010041226 * J-O-M PHAR                           
    RP5226    0002074G850001180FLOXIN 400MG TAB 100           0062-1542-01  EA00519010043251   J-O-M PHAR                           
    RP5226    0003074G955001180FLOXIN 400MG TAB 100           0062-1542-01  EA00519010024073 * J-O-M PHAR                           
    RP5196COST0140074001693ATUSS DM LIQ 16OZ              59702-015-16  EA00027500003300ATLEY PHAR 103                              
    RP5226    0024074G051001693ATUSS DM LIQ 16OZ              59702-015-16  EA00033000002750   ATLEY PHAR 103                       
    RP5226    0020074G150001693ATUSS DM LIQ 16OZ              59702-015-16  EA00033000002750   ATLEY PHAR 103                       
    RP5226    0001074G231001693ATUSS DM LIQ 16OZ              59702-015-16  EA00033000002750   ATLEY PHAR 103                       
    RP5226    0016074G619001693ATUSS DM LIQ 16OZ              59702-015-16  EA00033000002750   ATLEY PHAR 103                       
    RP5226    0098074G748001693ATUSS DM LIQ 16OZ              59702-015-16  EA00033000002750   ATLEY PHAR 103                       
    RP5226    0022074G840001693ATUSS DM LIQ 16OZ              59702-015-16  EA00033000002750   ATLEY PHAR 103                       
    RP5226    0040074G848001693ATUSS DM LIQ 16OZ              59702-015-16  EA00033000002750   ATLEY PHAR 103                       
    RP5226    0002074G850001693ATUSS DM LIQ 16OZ              59702-015-16  EA00033000002750   ATLEY PHAR 103                       
    RP5226    0003074G955001693ATUSS DM LIQ 16OZ              59702-015-16  EA00033000002750   ATLEY PHAR 103                       
    RP5196COST0140074002303DOBUTREX RTU 250MG VL 20ML     0002-7175-01  EA00010000001200LILLY ELI  7175                             
    RP5226    0024074G051002303DOBUTREX RTU 250MG VL 20ML     0002-7175-01  EA00012000001000   LILLY ELI  7175                      
    RP5226    0020074G150002303DOBUTREX RTU 250MG VL 20ML     0002-7175-01  EA00012000001000   LILLY ELI  7175                      
    RP5226    0001074G231002303DOBUTREX RTU 250MG VL 20ML     0002-7175-01  EA00012000001000   LILLY ELI  7175                      
    RP5226    0016074G619002303DOBUTREX RTU 250MG VL 20ML     0002-7175-01  EA00012000001000   LILLY ELI  7175                      
    RP5226    0098074G748002303DOBUTREX RTU 250MG VL 20ML     0002-7175-01  EA00012000001000   LILLY ELI  7175                      
    RP5226    0022074G840002303DOBUTREX RTU 250MG VL 20ML     0002-7175-01  EA00012000001000   LILLY ELI  7175                      
    RP5226    0040074G848002303DOBUTREX RTU 250MG VL 20ML     0002-7175-01  EA00012000001000   LILLY ELI  7175                      
    RP5226    0002074G850002303DOBUTREX RTU 250MG VL 20ML     0002-7175-01  EA00012000001000   LILLY ELI  7175                      
    RP5226    0003074G955002303DOBUTREX RTU 250MG VL 20ML     0002-7175-01  EA00012000000206 * LILLY ELI  7175                      
    RP5196COST0140074003228HEPARIN SOD 10MUN VL 5ML       0002-7217-01  EA00024340003042LILLY ELI  520                              
    RP5226    0024074G051003228HEPARIN SOD 10MUN VL 5ML       0002-7217-01  EA00030420002434   LILLY ELI  520                       
    RP5226    0020074G150003228HEPARIN SOD 10MUN VL 5ML       0002-7217-01  EA00030420002434   LILLY ELI  520                       
    RP5226    0001074G231003228HEPARIN SOD 10MUN VL 5ML       0002-7217-01  EA00030420002434   LILLY ELI  520                       
    RP5226    0016074G619003228HEPARIN SOD 10MUN VL 5ML       0002-7217-01  EA00030420002434   LILLY ELI  520                       
    RP5226    0098074G748003228HEPARIN SOD 10MUN VL 5ML       0002-7217-01  EA00030420002434   LILLY ELI  520                       
    RP5226    0022074G840003228HEPARIN SOD 10MUN VL 5ML       0002-7217-01  EA00030420002434   LILLY ELI  520                       
    RP5226    0040074G848003228HEPARIN SOD 10MUN VL 5ML       0002-7217-01  EA00030420002434   LILLY ELI  520                       
    RP5226    0002074G850003228HEPARIN SOD 10MUN VL 5ML       0002-7217-01  EA00030420002434   LILLY ELI  520                       
    RP5226    0003074G955003228HEPARIN SOD 10MUN VL 5ML       0002-7217-01  EA00030420001720 * LILLY ELI  520
    


    Sample Bat file:
    %jdkdir%\bin\java -jar Ibf.jar ccTest74.txt ccTemp.txt
    
    and control card input:
    IbfExtract
    inputSamp.txt
    x--output depends on col 1-10 and Group #
    x--line 1 is program (Class) to execute, line 2 is input file,   line 3 is output file,
    x--line 4 is print header line,          line 5 is Control Card, line 6 is separator line.  
    ---------------------------
    IbfRP5196
    RP5196COST
    dcost74.txt
     COST            74 3 N Y Y DCAT   N0140BBDC6300 ST. LOUIS STREET            MERIDIAN         MS39301 ATTN:MIKE PARTRIDGE            
    74   Y12X
    ----------------------------
    IbfRP5226
    RP5226.G051
    dprem74.txt
     PREMIER         74 3 N Y Y DCAT   N0024BBDC6300 ST. LOUIS STREET            MERIDIAN         MS39301 ATTN:MIKE PARTRIDGE 
    74G051 12X 
    -----------------------------
    


    Part of log file from 25 MB (200 KB record) extract to 9 files and two reports.
    IbfDrive--Copyright 2000, Imperial Business Forms & JSR Systems.  See: www.Jsrsys.com/copyright.
    IbfDrive--usage: IbfDrive  
    IbfDrive--Begin: 2002-02-28@17:40
    Open   Input: ccTest74.txt
    Open  Output: ccTemp.txt
    Close Output:          2 Records: ccTemp.txt                          
    Calling IbfExtract: test74
    IbfExtract--Copyright 2000, JSR Systems.  See: www.Jsrsys.com/copyright.
    IbfExtract--usage: IbfExtract 
    2002-02-28@17:40--RP5196 Begin Extract
    Open   Input: test74
    Open  Output: RP5196COST
    *RP5196COST[0]
    Open  Output: RP5226.G051
    *RP5226.G051[1]
    
    Open  Output: RP5226.G955
    *RP5226.G955[9]
    Close  Input:    198,775 Records: test74                                      
    Close Output:     19,869 Records: RP5196COST                          
    Close Output:     19,869 Records: RP5226.G051   
                           
    Close Output:     19,870 Records: RP5226.G955                          
    2002-02-28@17:40--RP5196 End-- Extract
    Open  Output: ccTemp.txt
    Close Output:          2 Records: ccTemp.txt                          
    Calling IbfRP5196: ccTemp.txt RP5196COST dcost74
    IbfRP5196--Copyright 2000, Imperial Business Forms & JSR Systems.  
    IbfRP5196--usage: IbfRP5196 <Control Card> <input> <output> 
    Open   Input: ccTemp.txt
    Open  Output: dcost74
    Close  Input:          2 Records: ccTemp.txt                                  
    Open   Input: RP5196COST
    year=2002 mm=12 Control Card=74   Y12X                               
    year=2002 mm=12
    Close  Input:     19,869 Records: RP5196COST                                  
    2002-02-28@17:40--RP5196COST Begin sort
    Sorting table of length: 19869
    Column/length/A-D): 95/1/0
    Column/length/A-D): 24/31/0
    2002-02-28@17:40--RP5196COST End-- sort
    Close Output:     20,855 Records: dcost74                          
     
    Close  Input:         18 Records: ccTest74.txt                                
    IbfDrive----End: 2002-02-28@17:40
    


    Sample Report 1:
     COST            74 3 N Y Y DCAT   N0140BBDC6300 ST. LOUIS STREET            MERIDIAN         MS39301 ATTN:MIKE PARTRIDGE            
    1                                                                                                                                    
    0    MERIDIAN DIVISION                       BERGEN BRUNSWIG CATALOG  DECEMBER 02 RP5196 PAGE     1                                  
          Item    Description                     N D C         Unit       Cost       List CL Vendor     Product Code                    
                                                                                                                                         
          001-693 ATUSS DM LIQ 16OZ               59702-015-16   EA       27.50      33.00    ATLEY PHAR 103                             
          002-303 DOBUTREX RTU 250MG VL 20ML      0002-7175-01   EA       10.00      12.00    LILLY ELI  7175                            
          001-180 FLOXIN 400MG TAB 100            0062-1542-01   EA      432.51     519.01    J-O-M PHAR                                 
          003-228 HEPARIN SOD 10MUN VL 5ML        0002-7217-01   EA       24.34      30.42    LILLY ELI  520                             
          001-172 METHYLENE BLU 1% SDV 10X10ML    0517-0310-10   EA       81.40     101.75    AMER REGEN                                 
    0Record Total =          5                                                                                                           
    
    


    Sample Report 2:
     PREMIER         74 3 N Y Y DCAT   N0024BBDC6300 ST. LOUIS STREET            MERIDIAN         MS39301 ATTN:MIKE PARTRIDGE            
    1                                                                                                                                    
    0 BG-G051 MERIDIAN DIVISION         BERGEN BRUNSWIG GROUP CATALOG  DECEMBER 02    PAGE    1    RP5226B                               
       Item    Description                     N D C         Unit      AWP       Cost Ind CL Vendor    Product Code                      
                                                                                                                                         
       001-693 ATUSS DM LIQ 16OZ               59702-015-16   EA     33.00      27.50        ATLEY PHA 103                               
       002-303 DOBUTREX RTU 250MG VL 20ML      0002-7175-01   EA     12.00      10.00        LILLY ELI 7175                              
       001-180 FLOXIN 400MG TAB 100            0062-1542-01   EA    519.01     423.86  *     J-O-M PHA                                   
       003-228 HEPARIN SOD 10MUN VL 5ML        0002-7217-01   EA     30.42      24.34        LILLY ELI 520                               
       001-172 METHYLENE BLU 1% SDV 10X10ML    0517-0310-10   EA    101.75      81.40        AMER REGE                                   
    0Record Total =          5                                                                                                           
    
    


    You have already seen snippets of code from IbfExtract above.
    Here is the report shell program (actually a complete program), and one of the classes that extend it.
    class IbfReport
    {
      static final String COPYRIGHT = 
      "Copyright 2000, Imperial Business Forms & JSR Systems.  See: www.Jsrsys.com/copyright.";
      static final int    MAXREC = 50000;
    
      JsrSysout sysout    = new JsrSysout();
      JsrUtil   u         = new JsrUtil();
      String[]    inputLine = new String[MAXREC];
      JsrLineIn   input   = new JsrLineIn();
      JsrSortByKey sort   = new JsrSortByKey();
      
      JsrLineOut output   = new JsrLineOut();
    
      int        line100  = 0;
      int     recNum      = 0;
      int     i           = 0;  
      int     iMax        = 0;
      int[]   keys;
      int testMax      = 0;  //setting to non-zero will process only first n records. 
      int pageNum      = 0;
      int lineCount    = 99;
      int linesPerPage = 84;
      
      String  tl1   = u.padRight("1",133);
      String  tl2   = u.padRight("0",133);
      String  tl2b  = " ";
      
      String hdr1   = u.padRight(" ",133);
      
      String today = u.getDateTime();
      String year4 = today.substring(0,4);
      String mm2   = today.substring(5,7);
      String[] mmName = {"  JANUARY",
                         " FEBRUARY",
                         "    MARCH",
                         "    APRIL",
                         "      MAY",
                         "     JUNE",
                         "     JULY",
                         "   AUGUST",
                         "SEPTEMBER",
                         "  OCTOBER",
                         " NOVEMBER",
                         " DECEMBER"};
      
      int    intYear;
      int    intMonth;
      String ccAll;
      String ccBrch;
      String ccHBGN;
      String ccCatType;
      String ccCostCode;
      String ccMonth;
      String ccPrtAcd;
      String division  = "    ";
      String costLabel = "    ";
      String reportName = "IbfReport";
    
    
        public static void main(String argv[])
        {
            IbfReport IbfReport = new IbfReport();  /** alternate: */ 
          //ibfReport variable should begin with lower-case!!!!!!  
            IbfReport.run(argv);
        }
        
        public void run(String parm[])
        {
          lineCount = 99;   // repeat of same report starts on new page.
          pageNum   =  0;   // start each report with new page numbers 2000-12-17
          setReportName();  // sets reportName for following displays, etc.
          setSortKeys();    // set sort keys array values...
          sysout.display(reportName+"--"+COPYRIGHT);
          sysout.display(reportName+"--usage: "+reportName+" <Control Card> <input> <output> ");
          /** alternate: above code should be in constructor */ 
    
          if (parm.length < 3)
          {
            sysout.display(reportName+"--requires three parameters");
            return;
          }
    
            input.setName(parm[0]); // set for control card input
            input.getNext(); // read first output "control card"  
           output.setName(parm[2]);
           out133(input.getLine());
            input.getNext(); // read control card.
            ccAll = u.padRight(input.getLine(),40);  // this eliminates IndexOutOfRange errors in setCC!
            input.setName(parm[1]);  // reset for datafile input
            
            setCC();  // sets Control Card (CC) fields
            
            if (ccBrch.equals("30")) division = "DALLAS DIVISION";
            if (ccBrch.equals("37")) division = "HOUSTON DIVISION";
            if (ccBrch.equals("72")) division = "MONTGOMERY DIVISION";
            if (ccBrch.equals("73")) division = "MOBILE DIVISION";
            if (ccBrch.equals("74")) division = "MERIDIAN DIVISION";
            if (ccBrch.equals("75")) division = "LAKELAND DIVISION";
            /** alternate: above could be a HashTable search */ 
    
            intYear    = u.getInt(year4);
            intMonth   = u.getInt(ccMonth);
            sysout.display("year="+intYear+" mm="+intMonth+" Control Card="+ccAll);
    
            if (intMonth < 1 || intMonth > 12)
            {
                sysout.display(reportName+"--Invalid month, terminating execution");
                System.exit(4);
            }
            if (mm2.equals("12") && ccMonth.equals("01")) intYear++;
            sysout.display("year="+intYear+" mm="+intMonth);
    
            setTl2();   // sets tl2 title line
                               
            setHdr1();  // sets hdr2 header
    
            
          i = 0;
          while (0 <= (recNum=input.getNext())) 
          {
             inputLine[i] = input.getLine();
             //sysout.display(inputLine[i]);
             iMax=i;
             i++;
             line100++;
             if (line100 == 100)
             {
                line100 = 0;
                sysout.speedometer("Loading record: "+recNum);
             }//sysout.display("Loading record: "+recNum+" iMax="+iMax);
             
             if (recNum == testMax) break; // set test EOF
          }
          iMax++;
          keys[0] = iMax;  // set actual table length.
          sysout.display(u.getDateTime()+"--"+parm[1]+" Begin sort");
          sort.sort(inputLine, keys);
          sysout.display(u.getDateTime()+"--"+parm[1]+" End-- sort");
    
    
          for (i = 0; i < iMax; i++)
          {
             //sysout.display(inputLine[i]);
    
             if (lineCount > linesPerPage) newPage();
             lineCount++;
             setDetail();  // method overridden 
          }
          out133("0"+"Record Total = " + u.padLeft(iMax,10) );
          
          output.close();
          
              
     
        }
        String picNum(String num)
        {
            int wholeInt;
            wholeInt = u.getInt(num);
            if (wholeInt == Integer.MIN_VALUE)
               return "     "+num.substring(0,5);
            else
               return u.padLeft(wholeInt,10,2);
        }
        void out133(String shortLine)
        {
            output.setLine(u.padRight(shortLine,133));
        }
            
        void newPage()
        {
            pageNum++;
            out133(tl1);
            out133(tl2+u.padLeft(pageNum,5)+tl2b);
            out133(hdr1);
            out133("                                               "); 
            lineCount = 4;
        }
    
    
        // it is expected the all the following methods will be overridden
        /** alternate: these should be defined as abstract methods */ 
    
        void setReportName()
        {
        }
    
        void setSortKeys()
        {
             keys = new int[] {0,1,1,0,};  // set default keys...
            //keys [0] = sort table length (actual), rest column,length,A/D  triplets
     
        }
    
        void setCC()
        {
        }
    
        void setTl2()
        {
        }
    
        void setHdr1()
        {
        }
    
        void setDetail()
        {
            out133("     ");
        }
    }
    
    
    
    class IbfRP5196 extends IbfReport { public static void main(String argv[]) { IbfRP5196 IbfRP5196 = new IbfRP5196(); IbfRP5196.run(argv); } void setReportName() { reportName = "IbfRP5196"; // this should be set to class name // used in displays } void setSortKeys() { keys = new int[] {0,95,1,0,24,31,0}; // descending on catalog, ascending on name //keys [0] = sort table length (actual), rest column,length,A/D triplets } void setCC() // this method defines location of Control Card fields. { ccBrch = ccAll.substring(0,2); ccHBGN = " "; ccCatType = ccAll.substring(2,5); ccCostCode = ccAll.substring(5,6); ccMonth = ccAll.substring(6,8); ccPrtAcd = ccAll.substring(8,9); }
    
          void setTl2()
          {
            tl2        = "0    "+u.padRight(division,40)
                               +u.padRight("BERGEN BRUNSWIG CATALOG",24)
                               +mmName[intMonth-1]+" "
                               +u.padZero(intYear,2)
                               +" RP5196 PAGE "
                               ;
          }
          void setHdr1()
          {
            if (ccCostCode.equals("Y")) costLabel = "Cost";
    
            hdr1       = "      "+u.padRight("Item",8)
                               +u.padRight("Description",32)
                               +u.padRight("N D C",14)
                               +u.padRight("Unit",5)
                               +u.padLeft(costLabel,10)+" "
                               +u.padLeft("List",10)+" CL "
                               +u.padRight("Vendor",11)
                               +           "Product Code"
                               ;
          }
    
    
          void setDetail()
          {
             out133("      "+
                inputLine[i].substring(17,20)+"-"+
                inputLine[i].substring(20,23)+" "+
                inputLine[i].substring(23,54)+" "+
                inputLine[i].substring(54,68)+" "+
                inputLine[i].substring(68,70)+"  "+
                picNum(inputLine[i].substring(70,77))+" "+
                picNum(inputLine[i].substring(77,84))+" "+
                inputLine[i].substring(94,95)+"  "+
                inputLine[i].substring(84,94)+" "+
                inputLine[i].substring(95,107) 
                
                           );
          }
        
    }
    




    Books that were helpful:

    "Java in 21 Days " by Laura Lemay (SAMS)
    "Java in a Nutshell" by David Flanagan (O'Reilly)
    "Java SWING " by Robert Eckstein, Marc Loy & Dave Wood (O'Reilly)
    "Java 2D Graphics" by Jonathan Knudsen (O'Reilly)





    Return to Table of Contents