Home > Software engineering >  Issues with enclosing PDDoucment
Issues with enclosing PDDoucment

Time:11-04

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.

CodePudding user response:

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.

CodePudding user response:

In case anyone is curious of the actual implementation of the solution I created an empty list.

List<PDDocument> activeDocuments = new ArrayList<PDDocument>();

And then everytime I called one of the methods I returned the document and stored it inside of the list and then closed them all at the end after I saved the original document.

  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();
                            activeDocuments.add(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();
                        activeDocuments.add(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) {
                            activeDocuments.add(statementsUtils.setPreLastPage(doc, activeDocument, currentIndex, transactionList, resBody, pageOf, pdf, header, maskedCard(cardNumber), generationDate));
                            pageNumber  ;
                            pageOf = "Page "   pageNumber.toString()   " of "   numberOfPages.toString();
                            activeDocuments.add(statementsUtils.setLastPage(doc, activeDocument, transactionList.size() - 1, transactionList, resBody, pageOf, pdf, header, maskedCard(cardNumber), generationDate));
                        } else {
                            activeDocuments.add(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 {
            PDPageContentStream contentStream = new PDPageContentStream(doc, page, PDPageContentStream.AppendMode.APPEND, true);
            contentStream.close();
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            if (doc != null) {
                doc.save(out);
                doc.close();
            }
            for (PDDocument a : activeDocuments)
                a.close();

            if (activeDocument != null) {
                activeDocument.close();
            }
            ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
            return in;
        }
  • Related