Sunday, April 26, 2009

Generate PDF report in ADF

Example is developed in Jdeveloper 10g. In this example I am using employee table from the HR schema and generating the pdf report which contains the first name ,last name and email address of the employee. I am making use of the Apache FOP. I am using the FOP version.95.Lets start with example. Create the application workspace with model and viewController projects. Add the following jar files in the viewController(Right click the viewController-->Project Properties-->Libraries--> Add Library -->New) :-
-->avalon-framework-4.2.0.jar
-->batik-all-1.7.jar
-->commons-io-1.3.1.jar
->custComps.jar
-->fop.jar
-->serializer-2.7.0.jar
-->xercesImpl-2.7.1.jar
-->xml-apis-1.3.04.jar
-->xml-apis-ext-1.3.04.jar
-->xmlgraphics-commons-1.3.1.jar
Create a read only view object with name "EmpVO" based on the employee table based on query
"SELECT
EMPLOYEES.EMPLOYEE_ID EMPLOYEE_ID,
EMPLOYEES.FIRST_NAME FIRST_NAME,
EMPLOYEES.LAST_NAME LAST_NAME,
EMPLOYEES.EMAIL EMAIL,
EMPLOYEES.PHONE_NUMBER PHONE_NUMBER,
EMPLOYEES.HIRE_DATE HIRE_DATE,
EMPLOYEES.SALARY SALARY
FROM EMPLOYEES".
Create a application module AppModule and add the above created view object in that.
The most difficult part in creating reports using FOP is you have to create the xsl fo file which defines the layout/formatting in which the xml data will be displayed in the pdf file.For this example I have developed following .xsl file:-
-----------------------------------------------------

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output method="xml" version="1.0" omit-xml-declaration="no"
indent="yes"/>
<xsl:template match="/">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="A4" page-width="297mm"
page-height="210mm" margin-top="0.5in"
margin-bottom="0.5in" margin-left="0.5in"
margin-right="0.5in">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="A4">
<fo:flow flow-name="xsl-region-body">
<fo:table table-layout="fixed" border-width="1mm"
border-style="solid">
<fo:table-column column-width="45mm"/>
<fo:table-column column-width="45mm"/>
<fo:table-column column-width="60mm"/>
<fo:table-header text-align="center" background-color="silver">
<fo:table-row>
<fo:table-cell padding="1mm" border-width="1mm"
border-style="solid">
<fo:block font-weight="bold">First Name</fo:block>
</fo:table-cell>
<fo:table-cell padding="1mm" border-width="1mm"
border-style="solid">
<fo:block font-weight="bold">Last Name</fo:block>
</fo:table-cell>
<fo:table-cell padding="1mm" border-width="1mm"
border-style="solid">
<fo:block font-weight="bold">Email Address</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-header>
<fo:table-body>
<xsl:for-each select="//EmpVORow">
<fo:table-row>
<fo:table-cell border-style="solid">
<fo:block>
<xsl:value-of select="FirstName"/>
</fo:block>
</fo:table-cell>
<fo:table-cell border-style="solid">
<fo:block>
<xsl:value-of select="LastName"/>
</fo:block>
</fo:table-cell>
<fo:table-cell border-style="solid">
<fo:block>
<xsl:value-of select="Email"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</fo:table>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
</xsl:stylesheet>
-----------------------------------------------------
Now create a JSPX page with one command button on it, on clicking which you will generate the PDF file and a command link on clicking which you will get the generated pdf.
<af:commandButton text="Generate XML" action="#{GenPDFBean.commandButton_action}" />
<h:commandLink value="Download PDF" action="#{GenPDFBean.downloadPDF}" target="_blank" />

Create a managed bean with name GenPDFBean and add the following code in the created bean.

import com.sun.java.util.collections.HashMap;

import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;


import java.io.OutputStream;
import java.io.PrintWriter;

import java.util.Map;

import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;

import model.AppModuleImpl;

import model.EmpVOImpl;

import oracle.adf.model.BindingContext;
import oracle.adf.model.binding.DCDataControl;
import oracle.adf.model.binding.DCUtil;
import oracle.adf.view.faces.context.AdfFacesContext;

import oracle.binding.BindingContainer;
import oracle.binding.OperationBinding;

import oracle.jbo.ApplicationModule;
import oracle.jbo.XMLInterface;

import java.io.Closeable;

import oracle.xml.parser.v2.XMLNode;

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants;

import org.w3c.dom.Node;

public class GenPDFBean {
private BindingContainer bindings;
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
AdfFacesContext context = AdfFacesContext.getCurrentInstance();
HttpServletRequest request =
(HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
BindingContext ctx = DCUtil.getBindingContext(request);
DCDataControl dc = ctx.findDataControl("AppModuleDataControl");
ApplicationModule service = (ApplicationModule)dc.getDataProvider();
ApplicationModule am = service.findApplicationModule("AppModule");
AppModuleImpl amImpl = (AppModuleImpl)am;
EmpVOImpl empVO = (EmpVOImpl)amImpl.findViewObject("EmpVO1");
private static final int DEFAULT_BUFFER_SIZE = 10240; // 10KB.

public GenPDFBean() {
}

public BindingContainer getBindings() {
return this.bindings;
}

public void setBindings(BindingContainer bindings) {
this.bindings = bindings;
}

public String commandButton_action() {
HashMap viewDefMap = new HashMap();
viewDefMap.put("model.EmpVO",
new String[] { "FirstName", "LastName", "Email" });
try {
//printXML(empVO.writeXML(-1,XMLInterface.XML_OPT_ALL_ROWS));
printXML(empVO.writeXML(XMLInterface.XML_OPT_ALL_ROWS,
viewDefMap));
generatePDF();
System.out.println("success");
} catch (IOException e) {
// TODO
}

return null;
}

private static void printXML(Node n) throws IOException {
//((XMLNode)n).print(System.out);
java.io.File file =
new java.io.File("C:/jdevstudio10133/jdev/mywork/FOP/ViewController/src/view/emp.xml");
//java.io.File file = new java.io.File("C:/Windows/Temp/emp.xml");
PrintWriter output = null;
try {
output = new java.io.PrintWriter(file);
((XMLNode)n).print(output);
} catch (IOException e) {
//throw new RuntimeException("IOExceptions will crash the application", e);
System.out.println(e.getMessage());
} catch (Exception e) {
System.out.println(e.getMessage());
} finally {
if (output != null) {
try {
output.close();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}

}


public void generatePDF() {
try {
System.out.println("FOP ExampleXML2PDF\n");
System.out.println("Preparing...");

// Setup directories
File baseDir = new File(".");
File outDir = new File(baseDir, "out");
outDir.mkdirs();

// Setup input and output files
File xmlfile =
new File("C:/jdevstudio10133/jdev/mywork/FOP/ViewController/src/view/emp.xml");
File xsltfile =
new File("C:/jdevstudio10133/jdev/mywork/FOP/ViewController/src/view/emp.xsl");
File pdffile =
new File("C:/jdevstudio10133/jdev/mywork/FOP/ViewController/src/view/EmpResultXML2PDF.pdf");

System.out.println("Input: XML (" + xmlfile + ")");
System.out.println("Stylesheet: " + xsltfile);
System.out.println("Output: PDF (" + pdffile + ")");
System.out.println();
System.out.println("Transforming...");

// configure fopFactory as desired
FopFactory fopFactory = FopFactory.newInstance();

FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
// configure foUserAgent as desired

// Setup output
OutputStream out = new java.io.FileOutputStream(pdffile);
out = new java.io.BufferedOutputStream(out);

try {
// Construct fop with desired output format
Fop fop =
fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent,
out);

// Setup XSLT
//TransformerFactory factory = TransformerFactory.newInstance();
TransformerFactory factory = new TransformerFactoryImpl();
Transformer transformer =
factory.newTransformer(new StreamSource(xsltfile));

// Set the value of a in the stylesheet
transformer.setParameter("versionParam", "2.0");

// Setup input for XSLT transformation
Source src = new StreamSource(xmlfile);

// Resulting SAX events (the generated FO) must be piped through to FOP
Result res = new SAXResult(fop.getDefaultHandler());

// Start XSLT transformation and FOP processing
transformer.transform(src, res);
} finally {
out.close();
}

System.out.println("Success!");
} catch (Exception e) {
e.printStackTrace(System.err);
//System.exit(-1);
}
}

public void downloadPDF() throws IOException {

// Prepare.
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
HttpServletResponse response =
(HttpServletResponse)externalContext.getResponse();

File file = new File(getFilePath(), getFileName());
BufferedInputStream input = null;
BufferedOutputStream output = null;

try {
// Open file.
input =
new BufferedInputStream(new FileInputStream(file), DEFAULT_BUFFER_SIZE);

// Init servlet response.
response.reset();
response.setContentType("application/pdf");
response.setContentLength((int)file.length());
//String fileName="ab2123";
response.setHeader("Content-disposition",
"inline; filename=\"" + getFileName() + "\"");
output =
new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE);

// Write file contents to response.
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
int length;
while ((length = input.read(buffer)) > 0) {
output.write(buffer, 0, length);
}

// Finalize task.
output.flush();
} finally {
// Gently close streams.
close((Closeable)output);
close((Closeable)input);
}

// Inform JSF that it doesn't need to handle response.
// This is very important, otherwise you will get the following exception in the logs:
// java.lang.IllegalStateException: Cannot forward after response has been committed.
facesContext.responseComplete();
}

private static void close(Closeable resource) {
if (resource != null) {
try {
resource.close();
} catch (IOException e) {
// Do your thing with the exception. Print it, log it or mail it. It may be useful to
// know that this will generally only be thrown when the client aborted the download.
e.printStackTrace();
}
}
}

private String getFilePath() {
return "C:\\jdevstudio10133\\jdev\\mywork\\FOP\\ViewController\\src\\view\\";
}

private String getFileName() {
return "EmpResultXML2PDF.pdf";
}

}

Tuesday, April 21, 2009

Unexpected null value for literal data

: ) my first post on web services. I faced this issue in Jdeveloper 10g.
Some times we developer’s faces an error during our developed, which irritates like anything. This will keep coming in office and in dreamsJ. For me the culprit was “unexpected null value for literal data”. You might be facing this error when you are sending request using web service proxy to server to perform some operation on the web service in question. This problem is not at the server side, but is thrown at the client side, when you are not setting the request fields to the web service.
Now the question is how you can identify that which fields are required for the web service. The answer is in the WSDL using which you have generated the web proxy. Open your WSDL and check against each element the value for the attribute minOccur. If it is equal to one, it means that element is mandatory. If minOccur is zero, it means is an optional element. And if minOccur attribute is missing, it will take the default value equal to “1” which means it’s mandatory.

If you have fairly large WSDL and its difficult to identify and set the values, just go ahead and change your WSDL with all elements attribute property minOccur set to “0”.