Question

I'm using Apache Fop with XSL-FO to generate a PDF. I'm then trying to stream the pdf as an attachment to apache.commons.mail.HtmlEmail; I receive emails with the attachment, however I get the following error. Length 0 bytes, encoding none. I'm able to create a pdf on the file system without any issue, so I know there is nothing wrong with the FOP portion of this code, so I'm not really sure why it's not working. Could someone tell me what I'm missing?

My code.

private void sendBroadcastNofications(PurchaseRequest pr) {
    try {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        //Fop sevice used to generate pdf.
        this.xmlPDFGeneratorService.generatePDF(pr, outputStream);
        byte[] bytes = outputStream.toByteArray();

        //I'm not sure if "application/pdf" would be an issue since fop is giving 
        //it the MimeConstants.MIME_PDF
        DataSource source = new ByteArrayDataSource(bytes, "application/pdf");            
        EmailAttachment attachment = new EmailAttachment(source, "purchase_requisition.pdf", "Broadcast Purcahse Requisition");

        Util.email("Purchase Request " + pr.getPrNumber(), getGenerateMessage(pr), pr.getAuthorizer().getEmail(), attachment);

    } catch (IOException ex) {
        Logger.getLogger(EmailServiceImpl.class.getName()).log(Level.SEVERE, null, ex);
    }
}


public static void email(String subject, String message, String recipient, EmailAttachment attachment) {
    email(subject, message, Collections.singleton(recipient), Collections.singleton(attachment));
}

public static void email(String subject, String message, Set<String> recipients, Set<EmailAttachment> attachments) {
    try {
        HtmlEmail email = new HtmlEmail();

        email.setHostName("mailhost");
        email.setSubject(subject);
        email.setHtmlMsg(message);
        email.setFrom("company@domain.com");

        for (EmailAttachment attachment : attachments) {
            try {
                email.attach(attachment.getDataSource(), attachment.getName(), attachment.getDescription());
            } catch (EmailException ex) {
                System.err.println("Email Attachment Exception: " + ex.getMessage());
            }
        }

        for (String recipient : recipients) {
            email.addTo(recipient);
        }
        email.send();
    } catch (EmailException ex) {
        System.err.println("Email Failed to Send: " + ex.getMessage());
    }
}

Fop Class

public class XMLPDFGeneratorServiceImpl implements XMLPDFGeneratorService {

private static final File baseDir = new File(".");
private static final File xsltfile = new File(baseDir, "./PurchaseRequestPDF.xsl");

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

public void generatePDF(PurchaseRequest pr, ByteArrayOutputStream outStream) {

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

    try {

        // Setup output
        outStream = new ByteArrayOutputStream();

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

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

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

        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        generateXML(pr, stream);  

        byte[] out = stream.toByteArray(); 
        stream.close();

        ByteArrayInputStream in = new ByteArrayInputStream(out);
        // Setup input for XSLT transformation
        Source src = new StreamSource(in);

        // 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);

    } catch (TransformerException ex) {
        Logger.getLogger(XMLPDFGeneratorServiceImpl.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IOException ex) {
        Logger.getLogger(XMLPDFGeneratorServiceImpl.class.getName()).log(Level.SEVERE, null, ex);
    } catch (FOPException ex) {
        Logger.getLogger(XMLPDFGeneratorServiceImpl.class.getName()).log(Level.SEVERE, null, ex);
    }
}

public void generateXML(PurchaseRequest pr, ByteArrayOutputStream stream) {
    try {
        // create JAXB context and instantiate marshaller
        JAXBContext context = JAXBContext.newInstance(PurchaseRequest.class);
        Marshaller m = context.createMarshaller();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        m.setProperty("com.sun.xml.bind.xmlDeclaration", Boolean.FALSE);
        m.marshal(pr, new PrintWriter(stream));
    } catch (JAXBException ex) {
        Logger.getLogger(XMLPDFGeneratorServiceImpl.class.getName()).log(Level.SEVERE, "JAXB Failed to produce xml stream", ex);
    }
}

}

Was it helpful?

Solution

you are overwriting the outStream in generatePDF(), therefore the one that you pass in stays empty. Remove that line and try again.

outStream = new ByteArrayOutputStream();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top