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
.