fop-0.95\fop -xml ..\data\xml\rpg.xml -xsl ..\data\xml\rpg.xsl c:\rpg.pdf
db2 'create alias MYLIB.myalias for MYLIB.QRPGLESRC(MYRPGPGM)' db2 'select SRCDTA from MYLIB.myalias'
ANT Build File
<project name="RPG2PDF" default="run" basedir="."> <property name="src" location="src/main/java"/> <property name="build" location="build"/> <property name="dist" location="dist"/> <property name="lib.dir" location="../lib/"/> <path id="classpath"> <fileset dir="${lib.dir}" includes="**/*.jar"/> </path> <target name="clean"> <delete dir="${build}"/> <delete dir="${dist}"/> </target> <target name="init" depends="clean"> <mkdir dir="${build}"/> <mkdir dir="${dist}"/> </target> <target name="compile" depends="init"> <javac srcdir="${src}" destdir="${build}" classpathref="classpath"/> </target> <target name="dist" depends="compile"> <jar jarfile="${dist}/${ant.project.name}.jar" basedir="${build}"> <manifest> <attribute name="Main-Class" value="PdfTransformer"/> </manifest> </jar> </target> <target name="run" depends="dist"> <java fork="true" classname="RpgPdfCreator"> <classpath> <path refid="classpath"/> <path location = "${dist}/${ant.project.name}.jar"/> </classpath> </java> </target> </project>
Main Class of JAR File
import java.io.File; public class RpgPdfCreator { public static void main(String... args) throws Exception { String srcFile = "UNBKT8F4/QRPGLESRC"; String srcMember = "FEE700R"; if (args.length != 0) { srcFile = args[0]; srcMember = args[1]; } File file = RpgReader.getData(srcFile, srcMember); PdfTransformer.createPdf(file); } }
Read the RPG Source Code By Executing SQL
import java.sql.Statement; import java.sql.ResultSet; import java.sql.DriverManager; import java.sql.SqlException; import java.io.FileNotFoundException; import java.io.IOException; import java.io.File; public class RpgReader { static Connection conn; public static Connection setConn() throws SQLException, ClassNotFoundException, IOException { String AS400SYSTEM="AS400DEV"; Class.forName("com.ibm.as400.access.AS400JDBCDriver"); conn = DriverManager.getConnection("jdbc:as400://" + AS400SYSTEM + ";naming=system;prompt=true"); return conn; } public static File getData(String srcFile, String srcMember) throws Exception { Statement stmt = null; ResultSet rs = null; try { conn = RpgReader.setConn(); stmt = conn.createStatement(); String sql = "create alias qtemp/myalias for " + srcFile + "(" + srcMember + ")"; stmt.execute(sql); rs = stmt.executeQuery("select srcdta from myalias"); File xmlFile = RpgToXml.getXmlFromResultSet(rs); return xmlFile; } finally { try { rs.close(); } catch(Exception e) {} try { stmt.close(); } catch(Exception e) {} try { conn.close(); } catch(Exception e) {} } } }
Wrap RPG Code in XML Tags
import java.sql.ResultSet; import java.io.File; import java.io.FileOutputStream; public class RpgToXml { static File getXmlFromResultSet(ResultSet rs) throws Exception { File file = new File("xml/rpg.xml"); FileOutputStream fos = new FileOutputStream(file); fos.write("<program>\n".getBytes()); while (rs.next()) { String s = rs.getString(1); s = s.replaceAll("<", "<") .replaceAll(">", ">") .replaceAll("&", "&") .replaceAll("'", "'") .substring(6,80); fos.write( ("<line>" + s + "</line>").getBytes() ); } fos.write("</program>".getBytes()); fos.flush(); return file; } }
Execute Apache FOP to Create PDF
import org.apache.fop.apps.FopFactory; import org.apache.fop.apps.Fop; import org.apache.fop.apps.MimeConstants; import javax.xml.transform.*; import javax.xml.transform.sax.*; import javax.xml.transform.stream.*; import java.io.*; /* Here is the basic pattern to render an XSL-FO file to PDF */ public class PdfTransformer { public static void createPdf(File xmlFile) throws Exception { OutputStream out = null; try { out = new BufferedOutputStream( new FileOutputStream(new File("rpg.pdf"))); Source xsl = new StreamSource(new File("xml/rpg.xsl")); Source src = new StreamSource(xmlFile); TransformerFactory factory = TransformerFactory.newInstance(); Transformer transformer = factory.newTransformer(xsl); FopFactory fopFactory = FopFactory.newInstance(); Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, out); Result result = new SAXResult(fop.getDefaultHandler()); transformer.transform(src, result); } finally { try { out.close(); } catch(Exception e) {} } } }
The Stylesheet, rpg.xsl
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"> <xsl:output method="xml" indent="yes"/> <xsl:param name="page-width">8.5in</xsl:param> <xsl:param name="page-height">11in</xsl:param> <xsl:param name="margin">2cm</xsl:param> <xsl:template match="/"> <fo:root> <fo:layout-master-set> <fo:simple-page-master master-name="A4-portrait" page-height="{$page-height}" page-width="{$page-width}" margin="{$margin}"> <fo:region-body/> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="A4-portrait"> <fo:flow flow-name="xsl-region-body"> <xsl:apply-templates/> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> <xsl:template match="program"> <fo:block> <xsl:apply-templates/> </fo:block> </xsl:template> <xsl:template match="line"> <fo:block font-family="monospace" white-space-collapse="false"> <xsl:apply-templates/> </fo:block> </xsl:template> </xsl:stylesheet>
Notes
For this example, I chose a simple, less robust design. Fewer parameters and more hard-coding make for a more concrete example which is easier to follow. The first thing to change is the name of the PDF that is produced to the name of the source member. This change should be made in PdfTransformer, the class that produces the PDF. Another change you may want to consider is landscape printing. You may find that some lines of RPG code are continued on another line in the PDF. You can exchange the width and height parameters in the XSL to get landscape format.I think the next thing to do with this code is to provide Google-like search capabilities of the code in the PDFs by adding Apache Lucene into the mix. The user should be able to request a search of the RPG code in the PDFs and receive a list of the PDFs in which any of the search terms appears. Apache Lucene can be run in a simple script just like Apache FOP. Of course, the documents won't be searched when the user makes his request. The search will essentially have been completed before the user requests it. We will use Apache Lucene to avoid costly document scans by building the search index as the RPG is read for the production of the PDF.