Skip to content
Advertisement

Issues with enclosing PDDoucment

I have implemented a program that will print data into a pdf however I am facing this issue

java.io.IOException: COSStream has been closed and cannot be read. Perhaps its enclosing PDDocument has been closed?

I know there have been similar issues posted but I could not find the solution to my problem from them. What I am doing is that I initialized two documents one of them being the main document(doc) the other for the rest of the pages and then I add to the main one(activeDocument), the service calls three different functions to add a new page one for the first page one for any pages in between, one for before the last and finally the last page.a Here is my code most of the logic can be ignored its mainly just the things relating to PDDocuments since thats where the issue lies

private InputStream generateCardsPDF(String cardNumber,
                                         String generationDate,
                                         StatementSummaryResTypeStatementSummaryResBody resBody,
                                         String pdf) throws IOException, ParseException {


        List<StatementSummaryResTypeStatementSummaryResBodyTransactionsTransaction> transactionList = resBody.getTransactions().getTransaction().stream().limit(50).collect(Collectors.toList());
        PDDocument doc = new PDDocument().load(getClass().getClassLoader().getResourceAsStream(pdf));
        PDDocumentCatalog docCatalog = doc.getDocumentCatalog();
        PDPage page = docCatalog.getPages().get(0);
        try {
            String fullName = resBody.getStatementHeader().getAddress().getTitle() +
                    " " + resBody.getStatementHeader().getAddress().getFirstName() + " ";
            String fullAddress = "";
            if (resBody.getStatementHeader().getAddress().getMiddleName() != null) {
                fullName = fullName + resBody.getStatementHeader().getAddress().getMiddleName() + " ";
            }

            fullName = fullName + resBody.getStatementHeader().getAddress().getLastName();


            String countryAddress = resBody.getStatementHeader().getAddress().getCity() != null ? resBody.getStatementHeader().getAddress().getCity() : "";
            countryAddress += resBody.getStatementHeader().getAddress().getCountry() != null &&
                    countryAddress.length() > 0 ? ", " + resBody.getStatementHeader().getAddress().getCountry() : "";
            countryAddress += resBody.getStatementHeader().getAddress().getCountry() != null &&
                    countryAddress.length() == 0 ? resBody.getStatementHeader().getAddress().getCountry() : "";

            fullAddress += resBody.getStatementHeader().getAddress().getAddress1() + ONE_LINE;
            fullAddress += resBody.getStatementHeader().getAddress().getAddress2() != null ? resBody.getStatementHeader().getAddress().getAddress2() + ONE_LINE : "";
            fullAddress += resBody.getStatementHeader().getAddress().getAddress3() != null ? resBody.getStatementHeader().getAddress().getAddress3() + ONE_LINE : "";
            fullAddress += countryAddress;

            String header = fullName + ONE_LINE + fullAddress;
            Integer currentIndex = 0;
            Integer count = 0;
            Integer cutOff = 0;
            Integer pageNumber = 1;
            Integer numberOfPages = statementsUtils.calculateNumberOfPages(transactionList, currentIndex, cutOff, count);
            String pageOf;
            PDDocument activeDocument = new PDDocument();
            statementsUtils.setFirstPage(transactionList, resBody, doc, header, maskedCard(cardNumber), generationDate, numberOfPages);
            try {
                while (currentIndex < transactionList.size()) {
                    Boolean fourOrFive = false;
                    Boolean checkpoint = false;
                    Boolean finalPrint = false;
                    if (count == 4) {
                        checkpoint = statementsUtils.reachedCheckpoint(currentIndex, transactionList);
                        if (checkpoint) {
                            cutOff = currentIndex;
                            fourOrFive = true;
                            pageNumber++;
                            pageOf = "Page " + pageNumber.toString() + " of " + numberOfPages.toString();
                            statementsUtils.addExtraPage(doc, activeDocument, cutOff, fourOrFive, transactionList, resBody, pageOf, pdf, header, maskedCard(cardNumber), generationDate);
                            count = 0;
                        }
                    } else if (count == 5) {
                        cutOff = currentIndex;
                        fourOrFive = false;
                        pageNumber++;
                        pageOf = "Page " + pageNumber.toString() + " of " + numberOfPages.toString();
                        statementsUtils.addExtraPage(doc, activeDocument, cutOff, fourOrFive, transactionList, resBody, pageOf, pdf, header, maskedCard(cardNumber), generationDate);
                        count = 0;
                    } else if (transactionList.size() <= 2) {
                        finalPrint = true;
                    } else if (transactionList.size() - currentIndex + 1 <= 5) { // count <4? print last page or count >=4 print 4 and check homuch left
                        finalPrint = true;
                        pageNumber++;
                        pageOf = "Page " + pageNumber.toString() + " of " + numberOfPages.toString();
                        if (transactionList.size() - currentIndex + 1 == 5) {
                            statementsUtils.setPreLastPage(doc, activeDocument, currentIndex, transactionList, resBody, pageOf, pdf, header, maskedCard(cardNumber), generationDate);
                            pageNumber++;
                            pageOf = "Page " + pageNumber.toString() + " of " + numberOfPages.toString();
                            statementsUtils.setLastPage(doc, activeDocument, transactionList.size() - 1, transactionList, resBody, pageOf, pdf, header, maskedCard(cardNumber), generationDate);
                        } else {
                            statementsUtils.setLastPage(doc, activeDocument, currentIndex - count + 1, transactionList, resBody, pageOf, pdf, header, maskedCard(cardNumber), generationDate);
                        }
                    }

                    if (fourOrFive && !finalPrint)
                        currentIndex = cutOff + 1;
                    else if (finalPrint)
                        currentIndex = transactionList.size();
                    else
                        currentIndex++;

                    if (currentIndex >= 2) count++;
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (activeDocument != null) {
                    activeDocument.close();
                }
            }
        } catch (IOException e) {

            e.printStackTrace();
        } finally {
            PDPageContentStream contentStream = new PDPageContentStream(doc, page, PDPageContentStream.AppendMode.APPEND, true);
            contentStream.close();
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            if (doc != null) {
                doc.save(out);
                doc.close();
            }
            ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
            return in;
        }

    }



  public void setFirstPage( PDDocument doc,....){
PDAcroForm acroForm = doc.getDocumentCatalog().getAcroForm();
...
acroForm.flatten();

}

      public void setPreLastPage( PDDocument doc, PDDocument activeDocument....){
     activeDocument = new PDDocument().load(getClass().getClassLoader().getResourceAsStream(pdf));
        PDDocumentCatalog docCatalog = activeDocument.getDocumentCatalog();
        PDPage p1 = docCatalog.getPages().get(0);
        PDAcroForm acroForm = docCatalog.getAcroForm();
        ...
        acroForm.flatten();
        PDPageContentStream cs = new PDPageContentStream(activeDocument, p1,PDPageContentStream.AppendMode.APPEND, true);
        cs.close();
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        activeDocument.save(out);
        doc.addPage(p1);
    
    }

      public void setLastPage( PDDocument doc, PDDocument activeDocument....){
     activeDocument = new PDDocument().load(getClass().getClassLoader().getResourceAsStream(pdf));
        PDDocumentCatalog docCatalog = activeDocument.getDocumentCatalog();
        PDPage p1 = docCatalog.getPages().get(0);
        PDAcroForm acroForm = docCatalog.getAcroForm();
        ...
        acroForm.flatten();
        PDPageContentStream cs = new PDPageContentStream(activeDocument, p1,PDPageContentStream.AppendMode.APPEND, true);
        cs.close();
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        activeDocument.save(out);
        doc.addPage(p1);
    
    }

      public void addExtraPage( PDDocument doc, PDDocument activeDocument....){
     activeDocument = new PDDocument().load(getClass().getClassLoader().getResourceAsStream(pdf));
        PDDocumentCatalog docCatalog = activeDocument.getDocumentCatalog();
        PDPage p1 = docCatalog.getPages().get(0);
        PDAcroForm acroForm = docCatalog.getAcroForm();
        ...
        acroForm.flatten();
        PDPageContentStream cs = new PDPageContentStream(activeDocument, p1,PDPageContentStream.AppendMode.APPEND, true);
        cs.close();
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        activeDocument.save(out);
        doc.addPage(p1);
    
    }

There is a lot more logic in these functions but I tried adding only what I thought is relevant.

I believe the issue is concerning either the content stream of one of the pdfs or the order in which I close, save etc…. but I couldn’t figure out what the exact issue is so any advice would be appreciated.

Advertisement

Answer

Three errors are in setPreLastPage, setLastPage, and addExtraPage: in each of these methods you load a new PDDocument in the respective local variable activeDocument, take a page from it and add it to the same PDDocument doc, and then drop all references to that PDDocument in activeDocument when leaving the respective method.

Dropping all references allows the garbage collection to pick these PDDocument instances up and close and remove them. This pulls away the data underneath the pages copied into the PDDocument doc, resulting in the error you observe when trying to save doc.

To prevent this either clone the page objects into doc before adding them or keep all these temporary documents open until you save doc.

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement