Oracle® Fusion Middleware Developer's Guide for Oracle Business Intelligence Publisher 11g Release 1 (11.1.1) Part Number E18863-01 |
|
|
View PDF |
Note:
The information in this chapter is intended to be used with the Oracle Fusion Middleware Java API Reference for Oracle Business Intelligence Publisher, which is available in the Oracle Fusion Middleware Business Intelligence Documentation Library. Also, this chapter assumes you are familiar with Java programming, XML, and XSL technologies.This chapter is for developers who want to create programs or applications that interact with BI Publisher through its Java application programming interface (API).
This chapter includes the following sections:
BI Publisher is made up of the following core API components:
PDF Form Processing Engine
Merges a PDF template with XML data (and optional metadata) to produce PDF document output. See Section 7.4, "PDF Form Processing Engine."
RTF Processor Engine
Converts an RTF template to XSL in preparation for input to the FO Engine. See Section 7.5, "RTF Processor Engine."
FO Processor Engine
Merges XSL and XML to produce any of the following output formats: Excel (HTML), PDF, RTF, or HTML. See Section 7.6, "FO Processor Engine."
PDF Document Merger
Provides optional postprocessing of PDF files to merge documents, add page numbering, and set watermarks. See Section 7.7, "PDF Document Merger."
eText Processor
Converts RTF eText templates to XSL and merges the XSL with XML to produce text output for EDI and EFT transmissions. See Section 7.10, "eText Processor."
Document Processor Engine (XML APIs)
Provides batch processing functionality to access a single API or multiple APIs by passing a single XML file to specify template names, data sources, languages, output type, output names, and destinations. See Section 7.11, "Document Processor Engine."
The following diagram illustrates the template type and output type options for each core processing engine:
Figure 7-1 Template and Output Types for BI Publisher Core Processing Engines
To use the BI Publisher APIs, ensure that xdocore.jar
is in your class path. xdocore.jar
contains the main library for the BI Publisher APIs.
In addition, the following libraries are required:
aolj.jar - version information for Oracle E-Business Suite
collections.jar - you only need this if you are working with the delivery APIs or bursting engine.
dvt-jclient.jar - a charting library
dvt-utils.jar - a charting library
groovy-all-1.6.3.jar - Groovy
i18nAPI_v3.jar - the i18n library used for localization functions
jewt4.jar - a charting support library
mail.jar - used for SMTP delivery
ojdl.jar - used for Oracle Diagnostic Logging
orai18n-collation.jar - used by XDK
orai18n-mapping.jar - used by XDK
orai18n.jar - contains character set and globalization support files used by XDK
osdt_cert.jar - security library for SMIME support
osdt_cms.jar - security library for SMIME support
osdt_core.jar - security library for SMIME support
osdt_smime.jar - security library for SMIME support
share.jar - a charting support library
xdoparser.jar - the scalable XML parser and XSLT 2.0 engine (10g)
xdoparser11g.jar - the scalable XML parser and XSLT 2.0 engine (11g)
xmlparserv2.jar - 11g XDK (SAX and DOM)
If you are using Oracle JDeveloper, then the charting and XML Parser libraries are available to you. However, it is recommended that you create a directory with all of the required JAR files to use as a custom library in your project. This will help prevent unexpected errors after deployment.
The easiest method to obtain the libraries is to download and install the Template Builder for Microsoft Word Add-in. Download the Template Builder for Word from the Home page, under Get Started, click Download BI Publisher Tools, then click Template Builder for Word.
The JAR files are packaged with the Template Builder in the jlib library under the install directory.
A sample path to the jlib would be:
C:\Program Files\Oracle\BI Publisher\BI Publisher Desktop\Template Builder for Word\jlib
Note that the Template Builder includes the aolj.jar. You must use the versioninfo.jar instead.
This section discusses how to use the RTP Processor Engine, and includes the following topics:
Section 7.4.3, "Merging XML Data with a PDF Template Using Input/Output File Name"
Section 7.4.4, "Merging XML Data with a PDF Template Using Input/Output Streams"
Section 7.4.5, "Merging an XML Data String with a PDF Template"
The PDF Form Processing Engine creates a PDF document by merging a PDF template with an XML data file. This can be done using file names, streams, or an XML data string.
As input to the PDF Processing Engine you can optionally include an XML-based Template MetaInfo (.xtm) file. This is a supplemental template to define the placement of overflow data.
The FO Processing Engine also includes utilities to provide information about your PDF template. You can:
Retrieve a list of field names from a PDF template
Convert XML data into XFDF using XSLT
XML data can be merged with a PDF template to produce a PDF output document in three ways:
Using input/output file names
Using input/output streams
Using an input XML data string
Input:
Template file name (String)
XML file name (String)
Output:
PDF file name (String)
Example 7-1 Sample Code for Merging XML Data with PDF Templates Using Input/Output File Names
import oracle.xdo.template.FormProcessor; . . FormProcessor fProcessor = new FormProcessor(); fProcessor.setTemplate(args[0]); // Input File (PDF) name fProcessor.setData(args[1]); // Input XML data file name fProcessor.setOutput(args[2]); // Output File (PDF) name fProcessor.process();
Input:
PDF Template (Input Stream)
XML Data (Input Stream)
Output:
PDF (Output Stream)
Example 7-2 Sample Code for Merging XML Data with PDF Templates Using Input/Output Streams
import java.io.*; import oracle.xdo.template.FormProcessor; . . . FormProcessor fProcessor = new FormProcessor(); FileInputStream fIs = new FileInputStream(originalFilePath); // Input File FileInputStream fIs2 = new FileInputStream(dataFilePath); // Input Data FileInputStream fIs3 = new FileInputStream(metaData); // Metadata XML Data FileOutputStream fOs = new FileOutputStream(newFilePath); // Output File fProcessor.setTemplate(fIs); fProcessor.setData(fIs2); // Input Data fProcessor.setOutput(fOs); fProcessor.process(); fIs.close(); fOs.close();
Input:
Template file name (String)
XML data (String)
Output:
PDF file name (String)
Example 7-3 Sample Code for Merging XML Data Strings with PDF Templates
import oracle.xdo.template.FormProcessor; . . . FormProcessor fProcessor = new FormProcessor(); fProcessor.setTemplate(originalFilePath); // Input File (PDF) name fProcessor.setDataString(xmlContents); // Input XML string fProcessor.setOutput(newFilePath); // Output File (PDF) name fProcessor.process();
Use the FormProcessor.getFieldNames() API to retrieve the field names from a PDF template. The API returns the field names into an Enumeration object.
Input:
PDF Template
Output:
Enumeration Object
Example 7-4 Sample Code for Retrieving a List of Field Names
import java.util.Enumeration; import oracle.xdo.template.FormProcessor; . . . FormProcessor fProcessor = new FormProcessor(); fProcessor.setTemplate(filePath); // Input File (PDF) name Enumeration enum = fProcessor.getFieldNames(); while(enum.hasMoreElements()) { String formName = (String)enum.nextElement(); System.out.println("name : " + formName + " , value : " + fProcessor.getFieldValue(formName)); }
XML Forms Data Format (XFDF) is a format for representing forms data and annotations in a PDF document. XFDF is the XML version of Forms Data Format (FDF), a simplified version of PDF for representing forms data and annotations. Form fields in a PDF document include edit boxes, buttons, and radio buttons.
Use this class to generate XFDF data. When you create an instance of this class, an internal XFDF tree is initialized. Use append() methods to append a FIELD element to the XFDF tree by passing a String name-value pair. You can append data as many times as you want.
This class also enables you to append XML data by calling appendXML() methods. Note that you must set the appropriate XSL style sheet by calling setStyleSheet() method before calling appendXML() methods. You can append XML data as many times as you want.
You can retrieve the internal XFDF document at any time by calling one of the following methods: toString(), toReader(), toInputStream(), or toXMLDocument().
The following is a sample of XFDF data:
Example 7-5 Sample XFDF Data
<?xml version="1.0" encoding="UTF-8"?> <xfdf xmlns="http://ns.adobe.com/xfdf/" xml:space="preserve"> <fields> <field name="TITLE"> <value>Purchase Order</value> </field> <field name="SUPPLIER_TITLE"> <value>Supplie</value> </field> ... </fields>
The following code example shows how you can use the API:
Example 7-6 Sample Code for Retrieving Internal XFDF Documents
import oracle.xdo.template.FormProcessor; import oracle.xdo.template.pdf.xfdf.XFDFObject; . . . FormProcessor fProcessor = new FormProcessor(); fProcessor.setTemplate(filePath); // Input File (PDF) name XFDFObject xfdfObject = new XFDFObject(fProcessor.getFieldInfo()); System.out.println(xfdfObject.toString());
Use an XSL style sheet to convert standard XML to the XFDF format. Following is an example of the conversion of sample XML data to XFDF:
Assume your starting XML has a ROWSET/ROW format as follows:
<ROWSET> <ROW num="0"> <SUPPLIER>Supplier</SUPPLIER> <SUPPLIERNUMBER>Supplier Number</SUPPLIERNUMBER> <CURRCODE>Currency</CURRCODE> </ROW> ... </ROWSET>
From this XML you want to generate the following XFDF format:
<fields> <field name="SUPPLIER1"> <value>Supplier</value> </field> <field name="SUPPLIERNUMBER1"> <value>Supplier Number</value> </field> <field name="CURRCODE1"> <value>Currency</value> </field> ... </fields>
The following XSLT will perform the transformation:
Example 7-7 Sample XLST for Transforming XML Data into XFDF Format
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <fields> <xsl:apply-templates/> </fields> </xsl:template> <!-- Count how many ROWs(rows) are in the source XML file. --> <xsl:variable name="cnt" select="count(//row|//ROW)" /> <!-- Try to match ROW (or row) element. <xsl:template match="ROW/*|row/*"> <field> <!-- Set "name" attribute in "field" element. --> <xsl:attribute name="name"> <!-- Set the name of the current element (column name)as a value of the current name attribute. --> <xsl:value-of select="name(.)" /> <!-- Add the number at the end of the name attribute value if more than 1 rows found in the source XML file.--> <xsl:if test="$cnt > 1"> <xsl:number count="ROW|row" level="single" format="1"/> </xsl:if> </xsl:attribute> <value> <!--Set the text data set in the current column data as a text of the "value" element. --> <xsl:value-of select="." /> </value> </field> </xsl:template> </xsl:stylesheet>
You can then use the XFDFObject to convert XML to the XFDF format using an XSLT as follows:
Example 7-8 Sample Code for Executing Transformation of XML Data into XFDF Format
import java.io.*; import oracle.xdo.template.pdf.xfdf.XFDFObject; . . . XFDFObject xfdfObject = new XFDFObject(); xfdfObject .setStylesheet(new BufferedInputStream(new FileInputStream(xslPath))); // XSL file name xfdfObject .appendXML( new File(xmlPath1)); // XML data file name xfdfObject .appendXML( new File(xmlPath2)); // XML data file name System.out.print(xfdfObject .toString());
This section discusses how to use the RTP Processor Engine, and includes the following topics:
The RTFProcessor can generate the pairing XLIFF file. The API example is as follows:
Example 7-9 Sample Code for Generating Pairing XLIFF Files
public static void main(String[] args) { RTFProcessor rtfp = new RTFProcessor(args[0]); //input RTF template rtfp.setOutput(args[1]); // XSL output file rtfp.setXLIFFOutput(args[2]); // XLIFF output file rtfp.process(); System.exit(0); }
To generate the translated report, call FOProcessor as follows:
The RTF processor engine takes an RTF template as input. The processor parses the template and creates an XSL-FO template. This can then be passed along with a data source (XML file) to the FO Engine to produce PDF, HTML, RTF, or Excel (HTML) output.
Use either input/output file names or input/output streams as shown in the following examples:
Input:
RTF file name (String)
Output:
XSL file name (String)
Example 7-11 Sample Code for Generating XSL with Input/Output File Names
import oracle.xdo.template.FOProcessor; . . . public static void main(String[] args) { RTFProcessor rtfProcessor = new RTFProcessor(args[0]); //input template rtfProcessor.setOutput(args[1]); // output file rtfProcessor.process(); System.exit(0); }
Input:
RTF (InputStream)
Output:
XSL (OutputStream)
Example 7-12 Sample Code for Generating XSL with Input/Output Streams
import oracle.xdo.template.FOProcessor; . . . public static void main(String[] args) { FileInputStream fIs = new FileInputStream(args[0]); //input template FileOutputStream fOs = new FileOutputStream(args[1]); // output RTFProcessor rtfProcessor = new RTFProcessor(fIs); rtfProcessor.setOutput(fOs); rtfProcessor.process(); // Closes inputStreams outputStream System.exit(0); }
This section discusses how to use the FO Processor Engine, and includes the following topics:
Section 7.6.2, "Generating Output from an XML File and an XSL File"
Section 7.6.5, "Generating Output from an Array of XSL Templates and XML Data"
The FO Processor Engine provides the following features:
BI Publisher utilizes the Unicode BiDi algorithm for BiDi layout. Based on specific values for the properties writing-mode, direction, and unicode bidi, the FO Processor supports the BiDi layout.
The writing-mode property defines how word order is supported in lines and order of lines in text. That is: right-to-left, top-to-bottom or left-to-right, top-to-bottom. The direction property determines how a string of text will be written: that is, in a specific direction, such as right-to-left or left-to-right. The unicode bidi controls and manages override behavior.
The FO Processor supports a two-level font fallback mechanism. This mechanism provides control over what default fonts to use when a specified font or glyph is not found. BI Publisher provides appropriate default fallback fonts automatically without requiring any configuration. BI Publisher also supports user-defined configuration files that specify the default fonts to use. For glyph fallback, the default mechanism will only replace the glyph and not the entire string.
For headers and footers that require more space than what is defined in the template, the FO Processor extends the regions and reduces the body region by the difference between the value of the page header and footer and the value of the body region margin.
This feature supports a "Z style" of horizontal table break. The horizontal table break is not sensitive to column span, so that if the column-spanned cells exceed the page (or area width), the FO Processor splits it and does not apply any intelligent formatting to the split cell.
The following figure shows a table that is too wide to display on a single page:
The following figure shows one option of how the horizontal table break will handle the wide table. In this example, a horizontal table break is inserted after the third column.
Figure 7-3 Example of Horizontal Table Break on Wide Table
The following figure shows another option. The table breaks after the third column, but includes the first column with each new page.
Figure 7-4 Example of Horizontal Table Break and Column Repeating on Wide Table
The FO Processor Engine is BI Publisher's implementation of the W3C XSL-FO standard. It does not represent a complete implementation of every XSL-FO component.
The FO Processor can generate output in PDF, RTF, HTML, or Excel (HTML) from either of the following input types:
Template (XSL) and Data (XML) combination
FO object
Input types can be passed as file names, streams, or in an array. Set the output format by setting the setOutputFormat() method to one of the following:
FORMAT_EXCEL
FORMAT_HTML
FORMAT_PDF
FORMAT_RTF
FORMAT_PPTX
FORMAT_MHTML
FORMAT_PPTMHT
FORMAT_EXCEL_MHTML
FORMAT_PDFZ
An XSL-FO utility is also provided that creates XSL-FO from the following inputs:
XSL file and XML file
Two XML files and two XSL files
Two XSL-FO files (merge)
The FO object output from the XSL-FO utility can then be used as input to the FO processor.
The following example shows how to use the FO Processor to create an output file using file names.
Input:
XML file name (String)
XSL file name (String)
Output:
Output file name (String)
Example 7-13 Sample Code for Generating Output Using File Names
import oracle.xdo.template.FOProcessor; . . . public static void main(String[] args) { FOProcessor processor = new FOProcessor(); processor.setData(args[0]); // set XML input file processor.setTemplate(args[1]); // set XSL input file processor.setOutput(args[2]); //set output file processor.setOutputFormat(FOProcessor.FORMAT_PDF); // Start processing try { processor.generate(); } catch (XDOException e) { e.printStackTrace(); System.exit(1); } System.exit(0); }
The processor can also be used with input/output streams as shown in the following example:
Input:
XML data (InputStream)
XSL data (InputStream)
Output:
Output stream (OutputStream)
Example 7-14 Sample Code for Generating Output Using Streams
import java.io.InputStream; import java.io.OutputStream; import oracle.xdo.template.FOProcessor; . . . public void runFOProcessor(InputStream xmlInputStream, InputStream xslInputStream, OutputStream pdfOutputStream) { FOProcessor processor = new FOProcessor(); processor.setData(xmlInputStream); processor.setTemplate(xslInputStream); processor.setOutput(pdfOutputStream); // Set output format (for PDF generation) processor.setOutputFormat(FOProcessor.FORMAT_PDF); // Start processing try { processor.generate(); } catch (XDOException e) { e.printStackTrace(); System.exit(1); } System.exit(0); }
An array of data and template combinations can be processed to generate a single output file from the multiple inputs. The number of input data sources must match the number of templates that are to be applied to the data. For example, an input of File1.xml, File2.xml, File3.xml and File1.xsl, File2.xsl, and File3.xsl will produce a single File1_File2_File3.pdf.
Input:
XML data (Array)
XSL data (template) (Array)
Output:
File Name (String)
Example 7-15 Sample Code for Generating Output from XSL Template Arrays and XML Data
import java.io.InputStream; import java.io.OutputStream; import oracle.xdo.template.FOProcessor; . . . public static void main(String[] args) { String[] xmlInput = {"first.xml", "second.xml", "third.xml"}; String[] xslInput = {"first.xsl", "second.xsl", "third.xsl"}; FOProcessor processor = new FOProcessor(); processor.setData(xmlInput); processor.setTemplate(xslInput); processor.setOutput("/tmp/output.pdf); //set (PDF) output file processor.setOutputFormat(FOProcessor.FORMAT_PDF); processor.process(); // Start processing try { processor.generate(); } catch (XDOException e) { e.printStackTrace(); System.exit(1); } }
Use the XSL-FO Utility to create an XSL-FO output file from input XML and XSL files, or to merge two XSL-FO files. You can use the output from this utility to generate your final output. See Section 7.6.2, "Generating Output from an XML File and an XSL File."
Input:
XML file
XSL file
Output:
XSL-FO (InputStream)
Example 7-16 Sample Code for Creating XSL-FO from XML and XSL Files
import oracle.xdo.template.fo.util.FOUtility; . . . public static void main(String[] args) { InputStream foStream; // creates XSL-FO InputStream from XML(arg[0]) // and XSL(arg[1]) filepath String foStream = FOUtility.createFO(args[0], args[1]); if (mergedFOStream == null) { System.out.println("Merge failed."); System.exit(1); } System.exit(0); }
Input:
XML File 1
XML File 2
XSL File 1
XSL File 2
Output:
XSL-FO (InputStream)
Example 7-17 Sample Code for Creating XSL-FO from Two XML Files and Two XSL Files
import oracle.xdo.template.fo.util.FOUtility; . . . public static void main(String[] args) { InputStream firstFOStream, secondFOStream, mergedFOStream; InputStream[] input = InputStream[2]; // creates XSL-FO from arguments firstFOStream = FOUtility.createFO(args[0], args[1]); // creates another XSL-FO from arguments secondFOStream = FOUtility.createFO(args[2], args[3]); // set each InputStream into the InputStream Array Array.set(input, 0, firstFOStream); Array.set(input, 1, secondFOStream); // merges two XSL-FOs mergedFOStream = FOUtility.mergeFOs(input); if (mergedFOStream == null) { System.out.println("Merge failed."); System.exit(1); } System.exit(0); }
Input:
Two XSL-FO file names (Array)
Output:
One XSL-FO (InputStream)
Example 7-18 Sample Code for Merging Two XSL-FO Files
import oracle.xdo.template.fo.util.FOUtility; . . . public static void main(String[] args) { InputStream mergedFOStream; // creates Array String[] input = {args[0], args[1]}; // merges two FO files mergedFOStream = FOUtility.mergeFOs(input); if (mergedFOStream == null) { System.out.println("Merge failed."); System.exit(1); } System.exit(0); }
The FO Processor can also be used to process an FO object to generate your final output. An FO object is the result of the application of an XSL-FO style sheet to XML data. These objects can be generated from a third party application and fed as input to the FO Processor.
The processor is called using a similar method to those already described, but a template is not required as the formatting instructions are contained in the FO.
Input:
FO file name (String)
Output:
PDF file name (String)
Example 7-19 Sample Code for Generating Output Using File Names
import oracle.xdo.template.FOProcessor; . . . public static void main(String[] args) { FOProcessor processor = new FOProcessor(); processor.setData(args[0]); // set XSL-FO input file processor.setTemplate((String)null); processor.setOutput(args[2]); //set (PDF) output file processor.setOutputFormat(FOProcessor.FORMAT_PDF); // Start processing try { processor.generate(); } catch (XDOException e) { e.printStackTrace(); System.exit(1); } System.exit(0); }
Input:
FO data (InputStream)
Output:
Output (OutputStream)
Example 7-20 Sample Code for Generating Output Using Streams
import java.io.InputStream; import java.io.OutputStream; import oracle.xdo.template.FOProcessor; . . . public void runFOProcessor(InputStream xmlfoInputStream, OutputStream pdfOutputStream) { FOProcessor processor = new FOProcessor(); processor.setData(xmlfoInputStream); processor.setTemplate((String)null); processor.setOutput(pdfOutputStream); // Set output format (for PDF generation) processor.setOutputFormat(FOProcessor.FORMAT_PDF); // Start processing try { processor.generate(); } catch (XDOException e) { e.printStackTrace(); System.exit(1); } }
Pass multiple FO inputs as an array to generate a single output file. A template is not required, therefore set the members of the template array to null, as shown in the example.
Input:
FO data (Array)
Output:
Output File Name (String)
Example 7-21 Sample Code for Generating Output with an Array of FO Data
import java.lang.reflect.Array; import oracle.xdo.template.FOProcessor; . . . public static void main(String[] args) { String[] xmlInput = {"first.fo", "second.fo", "third.fo"}; String[] xslInput = {null, null, null}; // null needs for xsl-fo input FOProcessor processor = new FOProcessor(); processor.setData(xmlInput); processor.setTemplate(xslInput); processor.setOutput("/tmp/output.pdf); //set (PDF) output file processor.setOutputFormat(FOProcessor.FORMAT_PDF); processor.process(); // Start processing try { processor.generate(); } catch (XDOException e) { e.printStackTrace(); System.exit(1); } }
The PDF Document Merger class provides a set of utilities to manipulate PDF documents. Using these utilities, you can merge documents, add page numbering, set backgrounds, and add watermarks.
Many business documents are composed of several individual documents that need to be merged into a single final document. The PDFDocMerger class supports the merging of multiple documents to create a single PDF document. This can then be manipulated further to add page numbering, watermarks, or other background images.
The following code demonstrates how to merge (concatenate) two PDF documents using physical files to generate a single output document.
Input:
PDF_1 file name (String)
PDF_2 file name (String)
Output:
PDF file name (String)
Example 7-22 Sample Code for Merging PDF Documents with Input/Output File Names
import java.io.*; import oracle.xdo.common.pdf.util.PDFDocMerger; . . . public static void main(String[] args) { try { // Last argument is PDF file name for output int inputNumbers = args.length - 1; // Initialize inputStreams FileInputStream[] inputStreams = new FileInputStream[inputNumbers]; inputStreams[0] = new FileInputStream(args[0]); inputStreams[1] = new FileInputStream(args[1]); // Initialize outputStream FileOutputStream outputStream = new FileOutputStream(args[2]); // Initialize PDFDocMerger PDFDocMerger docMerger = new PDFDocMerger(inputStreams, outputStream); // Merge PDF Documents and generates new PDF Document docMerger.mergePDFDocs(); docMerger = null; // Closes inputStreams and outputStream } catch(Exception exc) { exc.printStackTrace(); } }
Input:
PDF Documents (InputStream Array)
Output:
PDF Document (OutputStream)
Example 7-23 Merging PDF Documents with Input/Output Streams
import java.io.*; import oracle.xdo.common.pdf.util.PDFDocMerger; . . . public boolean mergeDocs(InputStream[] inputStreams, OutputStream outputStream) { try { // Initialize PDFDocMerger PDFDocMerger docMerger = new PDFDocMerger(inputStreams, outputStream); // Merge PDF Documents and generates new PDF Document docMerger.mergePDFDocs(); docMerger = null; return true; } catch(Exception exc) { exc.printStackTrace(); return false; } }
The following code demonstrates how to merge two PDF documents using input streams to generate a single merged output stream.
To add page numbers:
Create a background PDF template document that includes a PDF form field in the position that you would like the page number to appear on the final output PDF document.
Name the form field @pagenum@
.
Enter the number in the field from which to start the page numbering. If you do not enter a value in the field, the start page number defaults to 1.
Input:
PDF Documents (InputStream Array)
Background PDF Document (InputStream)
Output:
PDF Document (OutputStream)
Example 7-24 Sample Code for Merging PDF Documents with Background to Place Page Numbering
import java.io.*; import oracle.xdo.common.pdf.util.PDFDocMerger; . . . public static boolean mergeDocs(InputStream[] inputStreams, InputStream backgroundStream, OutputStream outputStream) { try { // Initialize PDFDocMerger PDFDocMerger docMerger = new PDFDocMerger(inputStreams, outputStream); // Set Background docMerger.setBackground(backgroundStream); // Merge PDF Documents and generates new PDF Document docMerger.mergePDFDocs(); docMerger = null; return true; } catch(Exception exc) { exc.printStackTrace(); return false; } }
The FO Processor supports page numbering natively through the XSL-FO templates, but if you are merging multiple documents you must use this class to number the complete document from beginning to end.
The following code example places page numbers in a specific point on the page, formats the numbers, and sets the start value using the following methods:
setPageNumberCoordinates (x, y) - sets the x and y coordinates for the page number position. The following example sets the coordinates to 300, 20.
setPageNumberFontInfo (font name, size) - sets the font and size for the page number. If you do not call this method, the default "Helvetica", size 8 is used. The following example sets the font to "Courier", size 8.
setPageNumberValue (n, n) - sets the start number and the page on which to begin numbering. If you do not call this method, the default values 1, 1 are used.
Input:
PDF Documents (InputStream Array)
Output:
PDF Document (OutputStream)
Example 7-25 Sample Code for Adding Page Numbers to Merged PDF Documents
import java.io.*; import oracle.xdo.common.pdf.util.PDFDocMerger; . . . public boolean mergeDocs(InputStream[] inputStreams, OutputStream outputStream) { try { // Initialize PDFDocMerger PDFDocMerger docMerger = new PDFDocMerger(inputStreams, outputStream); // Calls several methods to specify Page Number // Calling setPageNumberCoordinates() method is necessary to set Page Numbering // Please refer to javadoc for more information docMerger.setPageNumberCoordinates(300, 20); // If this method is not called, then the default font"(Helvetica, 8)" is used. docMerger.setPageNumberFontInfo("Courier", 8); // If this method is not called, then the default initial value "(1, 1)" is used. docMerger.setPageNumberValue(1, 1); // Merge PDF Documents and generates new PDF Document docMerger.mergePDFDocs(); docMerger = null; return true; } catch(Exception exc) { exc.printStackTrace(); return false; } }
Some documents that are in a draft phase require that a watermark indicating "DRAFT" be displayed throughout the document. Other documents might require a background image on the document. The following code sample shows how to use the PDFDocMerger class to set a watermark.
Use the SetTextDefaultWatermark() method to set a text watermark with the following attributes:
Text angle (in degrees): 55
Color: light gray (0.9, 0.9, 0.9)
Font: Helvetica
Font Size: 100
The start position is calculated based on the length of the text
Alternatively, use the SetTextWatermark() method to set each attribute separately. Use the SetTextWatermark() method as follows:
SetTextWatermark ("Watermark Text", x, y) - declare the watermark text, and set the x and y coordinates of the start position. In the following example, the watermark text is "Draft" and the coordinates are 200f, 200f.
setTextWatermarkAngle (n) - sets the angle of the watermark text. If this method is not called, 0 will be used.
setTextWatermarkColor (R, G, B) - sets the RGB color. If this method is not called, light gray (0.9, 0.9, 0.9) will be used.
setTextWatermarkFont ("font name", font size) - sets the font and size. If you do not call this method, Helvetica, 100 will be used.
The following example shows how to set these properties and then call the PDFDocMerger.
Input:
PDF Documents (InputStream)
Output:
PDF Document (OutputStream)
Example 7-26 Sample Code for Setting a Text Watermark in PDF Documents
import java.io.*; import oracle.xdo.common.pdf.util.PDFDocMerger; . . . public boolean mergeDocs(InputStream inputStreams, OutputStream outputStream) { try { // Initialize PDFDocMerger PDFDocMerger docMerger = new PDFDocMerger(inputStreams, outputStream); // You can use setTextDefaultWatermark() without these detailed setting docMerger.setTextWatermark("DRAFT", 200f, 200f); //set text and place docMerger.setTextWatermarkAngle(80); //set angle docMerger.setTextWatermarkColor(1.0f, 0.3f, 0.5f); // set RGB Color // Merge PDF Documents and generates new PDF Document docMerger.mergePDFDocs(); docMerger = null; return true; } catch(Exception exc) { exc.printStackTrace(); return false; } }
An image watermark can be set to cover the entire background of a document, or just to cover a specific area (for example, to display a logo). Specify the placement and size of the image using rectangular coordinates as follows:
float[] rct = {LowerLeft X, LowerLeft Y, UpperRight X, UpperRight Y}
For example:
float[] rct = {100f, 100f, 200f, 200f}
The image will be sized to fit the rectangular area defined.
To use the actual image size, without sizing it, define the LowerLeft X and LowerLeft Y positions to define the placement and specify the UpperRight X and UpperRight Y coordinates as -1f. For example:
float[] rct = {100f, 100f, -1f, -1f}
Input:
PDF Documents (InputStream)
Image File (InputStream)
Output:
PDF Document (OutputStream)
Example 7-27 Sample Code for Setting an Image Watermark in PDF Documents
import java.io.*; import oracle.xdo.common.pdf.util.PDFDocMerger; . . . public boolean mergeDocs(InputStream inputStreams, OutputStream outputStream, String imageFilePath) { try { // Initialize PDFDocMerger PDFDocMerger docMerger = new PDFDocMerger(inputStreams, outputStream); FileInputStream wmStream = new FileInputStream(imageFilePath); float[] rct = {100f, 100f, -1f, -1f}; pdfMerger.setImageWatermark(wmStream, rct); // Merge PDF Documents and generates new PDF Document docMerger.mergePDFDocs(); docMerger = null; // Closes inputStreams return true; } catch(Exception exc) { exc.printStackTrace(); return false; } }
The PDFBookBinder processor is useful for the merging of multiple PDF documents into a single document consisting of a hierarchy of chapters, sections, and subsections and a table of contents for the document. The processor also generates PDF style "bookmarks"; the outline structure is determined by the chapter and section hierarchy. The processor is extremely powerful allowing you complete control over the combined document.
The table of contents formatting and style is defined by an RTF template created in Microsoft Word. The chapters are passed into the program as separate PDF files (one chapter, section, or subsection corresponds to one PDF file). Templates may also be specified at the chapter level for insertion of dynamic or static content, page numbering, and placement of hyperlinks within the document.
The templates can be in RTF or PDF format. RTF templates are more flexible by allowing you to leverage BI Publisher's support for dynamic content. PDF templates are much less flexible, making it difficult to achieve desirable effects such as the reflow of text areas when inserting page numbers and other types of dynamic content.
The templates can be rotated (at right angles) or be made transparent. A PDF template can also be specified at the book level, enabling the ability to specify global page numbering, or other content such as backgrounds and watermarks. You can also pass as parameters a title page, cover page, and closing pages for each chapter or section.
The structure of the book's chapters, sections, and subsections is represented as XML and passed in as a command line parameter; or it can also be passed in at the API level. All of the chapter and section files, and all the templates files and their respective parameters, are specified inside this XML structure. Therefore, the only two required parameters are an XML file and a PDF output file.
You can also specify volume breaks inside the book structure. Specifying volume breaks will split the content up into separate output files for easier file and printer management.
The structure of the XML control file is represented in the following diagram:
To specify template and content file locations in your XML structure, you can specify a path relative to your local file system or you can specify a URL referring to the template or content location. Secure HTTP protocol is supported, as are specially recognized BI Publisher protocols, such as:
xdoxsl:/// used to load subtemplate.
"xdo://" - used to load other resources such as images.
Following is an example of the command line usage:
Example 7-28 Sample of Command Line Options
java oracle.xdo.template.pdf.book.PDFBookBinder [-debug <true or false>] [-tmp <temp dir>] -xml <input xml> -pdf <output pdf>
where
-xml <file>
is the file name of the input XML file containing the table of contents XML structure.
-pdf <file>
is the final generated PDF output file.
-tmp <directory>
is the temporary directory for better memory management. (This is optional, if not specified, the system environment variable "java.io.tmpdir"
will be used.)
-log <file>
sets the output log file (optional, default is System.out
).
-debug <true or false>
turns debugging off or on.
This section discusses how to use the PDF Digital Signature Engine, and includes the following topics:
The PDF Digital Signature Engine creates signed PDF documents by processing unsigned PDF documents with a signature field name and a password-protected Personal Information Exchange (PFX) file. PFX files adhere to the Public Key Cryptography Standards #12 (PCKS-12) format and contain a digital certificate and a corresponding private key.
To create signed PDF documents, see Section 7.9.2, "Signing PDF Documents."
To distribute or deliver signed PDF documents, use the Schedule Service. See Chapter 3, "ScheduleService."
To verify signed PDF documents, see Section 7.9.4, "Verifying Signed PDF Documents."
Signing a PDF document requires the following items:
A digital certificate. To obtain a digital certificate, see "Implementing Digital Signatures" in Oracle Fusion Middleware Developer's Guide for Oracle Business Intelligence Publisher.
A PFX file that contains your digital certificate.To create a PFX file, see "Implementing Digital Signatures" in Oracle Fusion Middleware Developer's Guide for Oracle Business Intelligence Publisher.
A PDF file with a signature field. If your PDF file does not contain a signature field, you can add one using the addSignatureField() method. Example 7-30 provides sample code for adding a signature field to a PDF file. This method saves the signature field in the PKCS-1 Secure Hash Algorithm #1 (SHA-1) format.
After you obtain or create the items listed above, you are ready to sign a PDF document.
To sign a PDF document, process your PDF file with your PFX file using the PDFSignature Java API that Oracle BI Publisher provides. Example 7-30 provides sample code for this purpose.
Example 7-30 Sample Code for Creating Signed PDF Documents
String workDir = "C:/projects/"; String inPDF = workDir + "VerySimpleContent.pdf"; String outPDF = workDir + "VerySimpleContent_signed.pdf"; String pkcs12File = workDir + "YourName.pfx"; try { PDFSignature pdfSignature = new PDFSignature(inPDF, outPDF); pdfSignature.init("password123", pkcs12File); // If your PDF document does not have a signature field, uncomment the // following line of code, which adds a signature field with the name // "Signature1". // pdfSignature.addSignatureField(1, PDFSignature.PDF_SIGNFIELD_UPPER_RIGHT, "Signature1“, -1, -1); pdfSignature.sign("Signature1", “Reason to Sign"); pdfSignature.cleanup(); } catch(Throwable t) { t.printStackTrace(); }
To distribute or deliver signed PDF documents, use the Schedule Service. See Chapter 3, "ScheduleService."
You can verify signed PDF documents by processing them with your digital certificate. Example 7-31 provides sample code for this purpose.
Example 7-31 Sample Code for Verifying Signed PDF Documents
String workDir = "C:/projects/"; String inPDF = workDir + "VerySimpleContent_signedWithAcrobat.pdf"; String trustedRootCert = workDir + "VerisignFreeCertificate.cer"; File trustedRootCertFile = new File(trustedRootCert); Vector trustedCerts = new Vector(); trustedCerts.addElement(trustedRootCertFile); try { PDFSignature pdfSignature = new PDFSignature(inPDF); pdfSignature.init(); SignatureFields signFields = pdfSignature.getSignatureFields(); Vector signedFieldNames = signFields.getSignatureFieldNames(); int size = signedFieldNames.size(); for(int i = 0 ; i < size ; i++) { String signFieldName = (String)signedFieldNames.elementAt(i); SignatureField signField = signFields.getSignatureField(signFieldName); boolean isValid = signField.verifyDocument(); System.out.println("Valid? : " + isValid); boolean isCertValid = signField.verifyCertificates(trustedCerts, null); System.out.println("Trusted? : " + isCertValid); } } catch(Throwable t) { t.printStackTrace(); }
The eText Processor enables you to convert RTF eText templates to XSL, and merge the XSL with XML to produce text output for EDI and EFT transmissions.
The following is an example of an API method call that converts an RTF eText template to XSL:
Example 7-32 Sample Code for Converting RTF eText Templates to XSL
String rtf = "test.rtf"; // etext template filename String xsl = "out.xsl"; // xsl-fo filename Properties prop = new Properties(); try { EFTProcessor p = new EFTProcessor(); p.setTemplate(rtf); p.setConfig(prop); p.setOutput(xsl); p.process(); } catch (Exception e) { e.printStackTrace(); }
The following is an example of an API method call that merges XSL with XML to produce eText output:
Example 7-33 Sample Code for Producing Text Output for EDI and EFT Transmissions
String rtf = "test.rtf"; // etext template filename String xml = “data.xml”; //xml data filename String etext = “etext.txt”; //etext output filename Properties prop = new Properties(); try { EFTProcessor p = new EFTProcessor(); p.setConfig(prop); p.setTemplate(rtf); p.setData(xml); p.setOutput(etext); p.process(); } catch (Exception e) { e.printStackTrace(); }
The Document Processor Engine provides batch processing functionality to access a single API or multiple APIs by passing a single XML instance document to specify template names, data sources, languages, output type, output names, and destinations.
This solution enables batch printing with BI Publisher, in which a single XML document can be used to define a set of invoices for customers, including the preferred output format and delivery channel for those customers. The XML format is very flexible allowing multiple documents to be created or a single master document.
This section:
Describes the hierarchy and elements of the Document Processor XML file
Provides sample XML files to demonstrate specific processing options
Provides example code to invoke the processors
The Document Processor XML file has the following element hierarchy:
Requestset request delivery filesystem print fax number email message document background text pagenumber template data
This hierarchy is displayed in the following illustration:
Figure 7-6 Hierarchy and Elements of the Document Processor XML File
The following table describes each of the elements:
Table 7-1 Elements in Document Processor XML File Hierarchy
Element | Attributes | Description |
---|---|---|
|
|
Root element must contain [ The |
|
N/A |
Element that contains the data and template processing definitions. |
|
N/A |
Defines where the generated output is sent. |
|
|
Specify one output that can have several template elements. The pdf (Default) rtf html excel text |
|
|
Specify this element to save the output to the file system. Define the directory path in the |
|
|
The |
|
|
Specify a URI in the |
|
The |
|
|
|
Specify the outgoing mail server (SMTP) in the Specify the mail server port in the |
|
|
The You can specify multiple e-mail addresses in the The The |
|
|
If the background text is required on a specific page, then set the |
|
|
Specify the watermark text in the A |
|
|
The The "Helvetica" is used for the page number font. The The |
|
|
Contains template information. Valid values for the rtf xsl-fo etext The default value is "pdf". |
|
|
Define the If the |
Following are sample XML files that show:
Simple XML shape
Defining two data sets
Defining multiple templates and data
Retrieving templates over HTTP
Retrieving data over HTTP
Generating more than one output
Defining page numbers
The following example shows how to define two data sources to merge with one template to produce one output file delivered to the file system:
Example 7-34 Sample XML for Defining Two Data Sets
<?xml version="1.0" encoding="UTF-8"?> <xapi:requestset xmlns:xapi="http://xmlns.oracle.com/oxp/xapi"> <xapi:request> <xapi:delivery> <xapi:filesystem output="d:\tmp\outfile.pdf"/> </xapi:delivery> <xapi:document output-type="pdf"> <xapi:template type="pdf" location="d:\mywork\template1.pdf"> <xapi:data> <field1>The first set of data</field1> </xapi:data> <xapi:data> <field1>The second set of data</field1> </xapi:data> </xapi:template> </xapi:document> </xapi:request> </xapi:requestset>
The following example builds on the previous examples by applying two data sources to one template and two data sources to a second template, and then merging the two into a single output file. Note that when merging documents, the output-type
must be "pdf".
Example 7-35 Sample XML for Defining Multiple Templates and Data
<?xml version="1.0" encoding="UTF-8"?> <xapi:requestset xmlns:xapi="http://xmlns.oracle.com/oxp/xapi"> <xapi:request> <xapi:delivery> <xapi:filesystem output="d:\tmp\outfile3.pdf"/> </xapi:delivery> <xapi:document output-type="pdf"> <xapi:template type="pdf" location="d:\mywork\template1.pdf"> <xapi:data> <field1>The first set of data</field1> </xapi:data> <xapi:data> <field1>The second set of data</field1> </xapi:data> </xapi:template> <xapi:template type="pdf" location="d:\mywork\template2.pdf"> <xapi:data> <field1>The third set of data</field1> </xapi:data> <xapi:data> <field1>The fourth set of data</field1> </xapi:data> </xapi:template> </xapi:document> </xapi:request> </xapi:requestset>
This sample is identical to the previous example, except in this case the two templates are retrieved over HTTP:
Example 7-36 Sample XML for Retrieving Templates over HTTP
<?xml version="1.0" encoding="UTF-8"?> <xapi:requestset xmlns:xapi="http://xmlns.oracle.com/oxp/xapi"> <xapi:request> <xapi:delivery> <xapi:filesystem output="d:\temp\out4.pdf"/> </xapi:delivery> <xapi:document output-type="pdf"> <xapi:template type="pdf" location="http://your.server:9999/templates/template1.pdf"> <xapi:data> <field1>The first page data</field1> </xapi:data> <xapi:data> <field1>The second page data</field1> </xapi:data> </xapi:template> <xapi:template type="pdf" location="http://your.server:9999/templates/template2.pdf"> <xapi:data> <field1>The third page data</field1> </xapi:data> <xapi:data> <field1>The fourth page data</field1> </xapi:data> </xapi:template> </xapi:document> </xapi:request> </xapi:requestset>
This sample builds on the previous example and shows one template with two data sources, all retrieved through HTTP; and a second template retrieved through HTTP with its two data sources embedded in the XML:
Example 7-37 Sample XML for Retrieving Data over HTTP
<?xml version="1.0" encoding="UTF-8"?> <xapi:requestset xmlns:xapi="http://xmlns.oracle.com/oxp/xapi"> <xapi:request> <xapi:delivery> <xapi:filesystem output="d:\temp\out5.pdf"/> </xapi:delivery> <xapi:document output-type="pdf"> <xapi:template type="pdf" location="http://your.server:9999/templates/template1.pdf"> <xapi:data location="http://your.server:9999/data/data_1.xml"/> <xapi:data location="http://your.server:9999/data/data_2.xml"/> </xapi:template> <xapi:template type="pdf" location="http://your.server:9999/templates/template2.pdf"> <xapi:data> <field1>The third page data</field1> </xapi:data> <xapi:data> <field1>The fourth page data</field1> </xapi:data> </xapi:template> </xapi:document> </xapi:request> </xapi:requestset>
The following sample shows the generation of two outputs: out_1.pdf
and out_2.pdf
. Note that a request
element is defined for each output.
Example 7-38 Sample XML for Generating More than One Output
<?xml version="1.0" encoding="UTF-8"?> <xapi:requestset xmlns:xapi="http://xmlns.oracle.com/oxp/xapi"> <xapi:request> <xapi:delivery> <xapi:filesystem output="d:\temp\out_1.pdf"/> </xapi:delivery> <xapi:document output-type="pdf"> <xapi:template type="pdf" location="d:\mywork\template1.pdf"> <xapi:data> <field1>The first set of data</field1> </xapi:data> <xapi:data> <field1>The second set of data</field1> </xapi:data> </xapi:template> </xapi:document> </xapi:request> <xapi:request> <xapi:delivery> <xapi:filesystem output="d:\temp\out_2.pdf"/> </xapi:delivery> <xapi:document output-type="pdf"> <xapi:template type="pdf" location="d:mywork\template2.pdf"> <xapi:data> <field1>The third set of data</field1> </xapi:data> <xapi:data> <field1>The fourth set of data</field1> </xapi:data> </xapi:template> </xapi:document> </xapi:request> </xapi:requestset>
The following sample shows the use of the pagenumber
element to define page numbers on a PDF output document. The first document that is generated will begin with an initial page number value of 1. The second output document will begin with an initial page number value of 3. The pagenumber
element can reside anywhere within the document
element tags.
Note that page numbering that is applied using the pagenumber
element will not replace page numbers that are defined in the template.
Example 7-39 Sample XML for Defining Page Numbers
<?xml version="1.0" encoding="UTF-8"?> <xapi:requestset xmlns:xapi="http://xmlns.oracle.com/oxp/xapi"> <xapi:request> <xapi:delivery> <xapi:filesystem output="d:\temp\out7-1.pdf"/> </xapi:delivery> <xapi:document output-type="pdf"> <xapi:pagenumber initial-value="1" initial-page-index="1" x-pos="300" y-pos="20" /> <xapi:template type="pdf" location="d:\mywork\template1.pdf"> <xapi:data> <field1>The first page data</field1> </xapi:data> <xapi:data> <field1>The second page data</field1> </xapi:data> </xapi:template> </xapi:document> </xapi:request> <xapi:request> <xapi:delivery> <xapi:filesystem output="d:\temp\out7-2.pdf"/> </xapi:delivery> <xapi:document output-type="pdf"> <xapi:template type="pdf" location="d:\mywork\template2.pdf"> <xapi:data> <field1>The third page data</field1> </xapi:data> <xapi:data> <field1>The fourth page data</field1> </xapi:data> </xapi:template> <xapi:pagenumber initial-value="3" initial-page-index="1" x-pos="300" y-pos="20" /> </xapi:document> </xapi:request> </xapi:requestset>
The following code samples show how to invoke the document processor engine using an input file name and an input stream.
Input:
Data file name (String)
Directory for Temporary Files (String)
Example 7-40 Sample Code for Invoking Processors with Input File Names
import oracle.xdo.batch.DocumentProcessor; . . . public static void main(String[] args) { . . . try { // dataFile --- File path of the Document Processor XML // tempDir --- Temporary Directory path DocumentProcessor docProcessor = new DocumentProcessor(dataFile, tempDir); docProcessor.process(); } catch(Exception e) { e.printStackTrace(); System.exit(1); } System.exit(0); }
Input:
Data file (InputStream)
Directory for Temporary Files (String)
Example 7-41 Sample Code for Invoking Processors with Input Streams
import oracle.xdo.batch.DocumentProcessor; import java.io.InputStream; . . . public static void main(String[] args) { . . . try { // dataFile --- File path of the Document Processor XML // tempDir --- Temporary Directory path FileInputStream fIs = new FileInputStream(dataFile); DocumentProcessor docProcessor = new DocumentProcessor(fIs, tempDir); docProcessor.process(); fIs.close(); } catch(Exception e) { e.printStackTrace(); System.exit(1); } System.exit(0); }
The FO Processor supports PDF security and other properties that can be applied to your final documents. Security properties include making a document unprintable and applying password security to an encrypted document.
Other properties allow you to define font subsetting and embedding. If your template uses a font that would not normally be available to BI Publisher at run time, you can use the font properties to specify the location of the font. At run time BI Publisher will retrieve and use the font in the final document. For example, this property might be used for check printing for which a MICR font is used to generate the account and routing numbers on the checks.
The properties can be set in the following ways:
At run time, specify the property as a Java Property object to pass to the FO Processor.
Set the property in a configuration file.
Set the property in the template (RTF templates only).
To pass a property as a Property object, set the name/value pair for the property before calling the FO Processor, as shown in the following example:
Input:
XML file name (String)
XSL file name (String)
Output:
PDF file name (String)
Example 7-42 Sample Code for Passing Properties to the FO Engine
import oracle.xdo.template.FOProcessor; . . . public static void main(String[] args) { FOProcessor processor = new FOProcessor(); processor.setData(args[0]); // set XML input file processor.setTemplate(args[1]); // set XSL input file processor.setOutput(args[2]); //set (PDF) output file processor.setOutputFormat(FOProcessor.FORMAT_PDF); Properties prop = new Properties(); /* PDF Security control: */ prop.put("pdf-security", "true"); /* Permissions password: */ prop.put("pdf-permissions-password", "abc"); /* Encryption level: */ prop.put("pdf-encription-level", "0"); processor.setConfig(prop); // Start processing try { processor.generate(); } catch (XDOException e) { e.printStackTrace(); System.exit(1); } System.exit(0); }
The following code shows an example of passing the location of a configuration file.
Input:
XML file name (String)
XSL file name (String)
Output:
PDF file name (String)
Example 7-43 Sample Code for Passing a Configuration File to the FO Processor
import oracle.xdo.template.FOProcessor; . . . public static void main(String[] args) { FOProcessor processor = new FOProcessor(); processor.setData(args[0]); // set XML input file processor.setTemplate(args[1]); // set XSL input file processor.setOutput(args[2]); //set (PDF) output file processor.setOutputFormat(FOProcessor.FORMAT_PDF); processor.setConfig("/tmp/xmlpconfig.xml"); // Start processing try { processor.generate(); } catch (XDOException e) { e.printStackTrace(); System.exit(1); } System.exit(0); }
Input:
Data file name (String)
Directory for Temporary Files (String)
Output:
PDF FIle
Example 7-44 Sample Code for Passing Properties to the Document Processor
import oracle.xdo.batch.DocumentProcessor; . . . public static void main(String[] args) { . . . try { // dataFile --- File path of the Document Processor XML // tempDir --- Temporary Directory path DocumentProcessor docProcessor = new DocumentProcessor(dataFile, tempDir); Properties prop = new Properties(); /* PDF Security control: */ prop.put("pdf-security", "true"); /* Permissions password: */ prop.put("pdf-permissions-password", "abc"); /* encryption level: */ prop.put("pdf-encription-level", "0"); processor.setConfig(prop); docProcessor.process(); } catch(Exception e) { e.printStackTrace(); System.exit(1); } System.exit(0); }
For the advanced formatting to work in the template, you must provide a Java class with the appropriate methods to format the data at run time. Many font vendors offer the code with their fonts to perform the formatting; these must be incorporated as methods into a class that is available to the BI Publisher formatting libraries at run time. There are some specific interfaces that you must provide in the class for the library to call the correct method for encoding.
If you use one of the three barcodes provided with BI Publisher, you do not need to provide the Java class. For more information see "Using the Barcode Fonts Shipped with BI Publisher" in the Oracle Fusion Middleware Report Designer's Guide for Oracle Business Intelligence Publisher.
You must implement the following methods in this class:
/** * Return a unique ID for this barcode encoder * @return the id as a string */ public String getVendorID(); /** * Return true if this encoder support a specific type of barcode * @param type the type of the barcode * @return true if supported */ public boolean isSupported(String type); /** * Encode a barcode string by given a specific type * @param data the original data for the barcode * @param type the type of the barcode * @return the formatted data */ public String encode(String data, String type);
Place this class in the classpath for the middle tier JVM in which BI Publisher is running.
For E-Business Suite users, the class must be placed in the classpath for the middle tier and any concurrent nodes that are present.
If in the register-barcode-vendor command the barcode_vendor_id
is not provided, BI Publisher will call the getVendorID() and use the result of the method as the ID for the vendor.
The following is an example class that supports the code128 a, b, and c encodings:
The following code sample can be copied and pasted for use in your system. Note that due to publishing constraints you will need to correct line breaks and ensure that you delete quotes that display as "smart quotes" and replace them with simple quotes.
Example 7-45 Sample Code for Advanced Barcode Formatting
package oracle.xdo.template.rtf.util.barcoder; import java.util.Hashtable; import java.lang.reflect.Method; import oracle.xdo.template.rtf.util.XDOBarcodeEncoder; import oracle.xdo.common.log.Logger; // This class name will be used in the register vendor // field in the template. public class BarcodeUtil implements XDOBarcodeEncoder // The class implements the XDOBarcodeEncoder interface { // This is the barcode vendor id that is used in the // register vendor field and format-barcode fields public static final String BARCODE_VENDOR_ID = "XMLPBarVendor"; // The hashtable is used to store references to // the encoding methods public static final Hashtable ENCODERS = new Hashtable(10); // The BarcodeUtil class needs to be instantiated public static final BarcodeUtil mUtility = new BarcodeUtil(); // This is the main code that is executed in the class, // it is loading the methods for the encoding into the hashtable. // In this case we are loading the three code128 encoding // methods we have created. static { try { Class[] clazz = new Class[] { "".getClass() }; ENCODERS.put("code128a",mUtility.getClass().getMethod("code128a", clazz)); ENCODERS.put("code128b",mUtility.getClass().getMethod("code128b", clazz)); ENCODERS.put("code128c",mUtility.getClass().getMethod("code128c", clazz)); } catch (Exception e) { // This is using the BI Publisher logging class to push // errors to the XMLP log file. Logger.log(e,5); } } // The getVendorID method is called from the template layer // at runtime to ensure the correct encoding method are used public final String getVendorID() { return BARCODE_VENDOR_ID; } //The isSupported method is called to ensure that the // encoding method called from the template is actually // present in this class. // If not then XMLP will report this in the log. public final boolean isSupported(String s) { if(s != null) return ENCODERS.containsKey(s.trim().toLowerCase()); else return false; } // The encode method is called to then call the appropriate // encoding method, in this example the code128a/b/c methods. public final String encode(String s, String s1) { if(s != null && s1 != null) { try { Method method = (Method)ENCODERS.get(s1.trim().toLowerCase()); if(method != null) return (String)method.invoke(this, new Object[] { s }); else return s; } catch(Exception exception) { Logger.log(exception,5); } return s; } else { return s; } } /** This is the complete method for Code128a */ public static final String code128a( String DataToEncode ) { char C128_Start = (char)203; char C128_Stop = (char)206; String Printable_string = ""; char CurrentChar; int CurrentValue=0; int weightedTotal=0; int CheckDigitValue=0; char C128_CheckDigit='w'; DataToEncode = DataToEncode.trim(); weightedTotal = ((int)C128_Start) - 100; for( int i = 1; i <= DataToEncode.length(); i++ ) { //get the value of each character CurrentChar = DataToEncode.charAt(i-1); if( ((int)CurrentChar) < 135 ) CurrentValue = ((int)CurrentChar) - 32; if( ((int)CurrentChar) > 134 ) CurrentValue = ((int)CurrentChar) - 100; CurrentValue = CurrentValue * i; weightedTotal = weightedTotal + CurrentValue; } //divide the WeightedTotal by 103 and get the remainder, //this is the CheckDigitValue CheckDigitValue = weightedTotal % 103; if( (CheckDigitValue < 95) && (CheckDigitValue > 0) ) C128_CheckDigit = (char)(CheckDigitValue + 32); if( CheckDigitValue > 94 ) C128_CheckDigit = (char)(CheckDigitValue + 100); if( CheckDigitValue == 0 ){ C128_CheckDigit = (char)194; } Printable_string = C128_Start + DataToEncode + C128_CheckDigit + C128_Stop + " "; return Printable_string; } /** This is the complete method for Code128b ***/ public static final String code128b( String DataToEncode ) { char C128_Start = (char)204; char C128_Stop = (char)206; String Printable_string = ""; char CurrentChar; int CurrentValue=0; int weightedTotal=0; int CheckDigitValue=0; char C128_CheckDigit='w'; DataToEncode = DataToEncode.trim(); weightedTotal = ((int)C128_Start) - 100; for( int i = 1; i <= DataToEncode.length(); i++ ) { //get the value of each character CurrentChar = DataToEncode.charAt(i-1); if( ((int)CurrentChar) < 135 ) CurrentValue = ((int)CurrentChar) - 32; if( ((int)CurrentChar) > 134 ) CurrentValue = ((int)CurrentChar) - 100; CurrentValue = CurrentValue * i; weightedTotal = weightedTotal + CurrentValue; } //divide the WeightedTotal by 103 and get the remainder, //this is the CheckDigitValue CheckDigitValue = weightedTotal % 103; if( (CheckDigitValue < 95) && (CheckDigitValue > 0) ) C128_CheckDigit = (char)(CheckDigitValue + 32); if( CheckDigitValue > 94 ) C128_CheckDigit = (char)(CheckDigitValue + 100); if( CheckDigitValue == 0 ){ C128_CheckDigit = (char)194; } Printable_string = C128_Start + DataToEncode + C128_CheckDigit + C128_Stop + " "; return Printable_string; } /** This is the complete method for Code128c **/ public static final String code128c( String s ) { char C128_Start = (char)205; char C128_Stop = (char)206; String Printable_string = ""; String DataToPrint = ""; String OnlyCorrectData = ""; int i=1; int CurrentChar=0; int CurrentValue=0; int weightedTotal=0; int CheckDigitValue=0; char C128_CheckDigit='w'; DataToPrint = ""; s = s.trim(); for(i = 1; i <= s.length(); i++ ) { //Add only numbers to OnlyCorrectData string CurrentChar = (int)s.charAt(i-1); if((CurrentChar < 58) && (CurrentChar > 47)) { OnlyCorrectData = OnlyCorrectData + (char)s.charAt(i-1); } } s = OnlyCorrectData; //Check for an even number of digits, add 0 if not even if( (s.length() % 2) == 1 ) { s = "0" + s; } //<<<< Calculate Modulo 103 Check Digit and generate // DataToPrint >>>> //Set WeightedTotal to the Code 128 value of // the start character weightedTotal = ((int)C128_Start) - 100; int WeightValue = 1; for( i = 1; i <= s.length(); i += 2 ) { //Get the value of each number pair (ex: 5 and 6 = 5*10+6 =56) //And assign the ASCII values to DataToPrint CurrentChar = ((((int)s.charAt(i-1))-48)*10) + (((int)s.charAt(i))-48); if((CurrentChar < 95) && (CurrentChar > 0)) DataToPrint = DataToPrint + (char)(CurrentChar + 32); if( CurrentChar > 94 ) DataToPrint = DataToPrint + (char)(CurrentChar + 100); if( CurrentChar == 0) DataToPrint = DataToPrint + (char)194; //multiply by the weighting character //add the values together to get the weighted total weightedTotal = weightedTotal + (CurrentChar * WeightValue); WeightValue = WeightValue + 1; } //divide the WeightedTotal by 103 and get the remainder, //this is the CheckDigitValue CheckDigitValue = weightedTotal % 103; if((CheckDigitValue < 95) && (CheckDigitValue > 0)) C128_CheckDigit = (char)(CheckDigitValue + 32); if( CheckDigitValue > 94 ) C128_CheckDigit = (char)(CheckDigitValue + 100); if( CheckDigitValue == 0 ){ C128_CheckDigit = (char)194; } Printable_string = C128_Start + DataToPrint + C128_CheckDigit + C128_Stop + " "; Logger.log(Printable_string,5); return Printable_string; } }
Once you create the class and place it in the correct classpath, your template creators can start using it to format the data for barcodes. You must give them the following information to include in the template commands:
The class name and path.
In this example:
oracle.xdo.template.rtf.util.barcoder.BarcodeUtil
The barcode vendor ID you created.
In this example: XMLPBarVendor
The available encoding methods.
In this example, code128a, code128b and code128c They can then use this information to successfully encode their data for barcode output.
They can then use this information to successfully encode their data for barcode output.