2
votes

I have SSJS in a button that opens a pdf file, writes to some fields on it (Acroform) and then downloads the file to the user. All works great (using pdfbox) but I wanted to be a good programmer and if the original pdf file was not available then cancel the operation. Otherwise, the user still gets prompted to open the file but Adobe Reader reports the file is corrupted (obviously it will be). I do my pdf operations in a Java class that I call and pass in the outputStream of the response object. Below is my SSJS. If I test the ret value from newVal.outputPdf and put all the other code in the if statement then my XPage is just blank. I assume because the response and outputStream was already opened?

Howard

importPackage(com.tlcc);
var newVal = new PdfBoxTest();
importPackage(java.net);
importPackage(java.lang);
var con = facesContext.getExternalContext();
var response:com.ibm.xsp.webapp.XspHttpServletResponse = con.getResponse();

try {           
var writer:javax.servlet.ServletOutputStream = response.getOutputStream();


//get the stream
var ret = newVal.outputPdf(writer, "http://localhost/pdfexportcc.nsf/certificate.pdf");

// setting response headers for browser
print("Good output");
response.setContentType("application/pdf");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", -1);
response.setHeader( "Content-Disposition", "attachment; filename=\"mypdf.pdf\"" );
writer.flush();
writer.close();
print("in close");
facesContext.responseComplete();
} catch (e) {
    var errorMessage = "An error has occured: " + e.toString();
    _dump(errorMessage); 
    writer.close();
    response.sendError(500, errorMessage);
}

Tried again with all the work being done in Java. I called this method from a button. Works fine with a valid url but when the url is bad it throws an error. Exception Can't get a Writer while an OutputStream is already in use.

public boolean outputAllInJavaPdf() {
    try {
        FacesContext context = FacesContext.getCurrentInstance();

        XspHttpServletResponse response = (XspHttpServletResponse) context.getExternalContext().getResponse();

        ServletOutputStream writer = response.getOutputStream();
        InputStream docUrl = new URL("http://localhost/pdfexportcc.nsf/certifxxicate.pdf").openStream();
        pdfDoc = PDDocument.load(docUrl);

        System.out.println("Number of pages is " + pdfDoc.getNumberOfPages());
        setField("Student", "James Namce");
        setField("CourseName", "XPages Development 2 for Notes and Domino 9");
        setField("Instructor", "John Smith");
        System.out.println("After set field");
        pdfDoc.save(writer);
        pdfDoc.close();

        response.setContentType("application/pdf");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", -1);
        response.setHeader("Content-Disposition", "attachment; filename=\"mypdf.pdf\"");
        writer.flush();
        writer.close();

        context.responseComplete();
        return true;

    } catch (Exception e) {
        System.out.println(e.getMessage());
        e.printStackTrace();
        return false;
    }
}
2

2 Answers

1
votes

All depends on what you tell the browser.

You use content type of PDF file. Browser opens (downloads) PDF file. Anything you put inside, for example error page, is treated as content of PDF file. So in case PDF generation fails, do not set that content type and redirect browser to error page, or back to original XPage with explanation.

public boolean outputAllInJavaPdf() {
    try {
        FacesContext context = FacesContext.getCurrentInstance();

        XspHttpServletResponse response = (XspHttpServletResponse) context.getExternalContext().getResponse();

        ServletOutputStream writer = response.getOutputStream();
        boolean servePdf = true;
        try {
            InputStream docUrl = new URL("http://localhost/pdfexportcc.nsf/certifxxicate.pdf").openStream();
            pdfDoc = PDDocument.load(docUrl);
            // do something to validate PDF
        } catch (Exception e) {
            //no PDF
            servePdf = false;
        }

        if (servePdf) {
            System.out.println("Number of pages is " + pdfDoc.getNumberOfPages());
            setField("Student", "James Namce");
            setField("CourseName", "XPages Development 2 for Notes and Domino 9");
            setField("Instructor", "John Smith");
            System.out.println("After set field");
            pdfDoc.save(writer);
            pdfDoc.close();

            response.setContentType("application/pdf");
            response.setHeader("Cache-Control", "no-cache");
            response.setDateHeader("Expires", -1);
            response.setHeader("Content-Disposition", "attachment; filename=\"mypdf.pdf\"");

        } else {
            // take care of no PDF response - redirect?
        }
            writer.flush();
            writer.close();
            context.responseComplete();
            return true;
    } catch (Exception e) {
        System.out.println(e.getMessage());
        e.printStackTrace();
        return false;
    }
}
0
votes

It is probably trying to render your Xpage, but you want to control the response yourself. To prevent rendering of the Xpage and take control of the writer, add rendered="false"to your Xpage.