2012-09-20 4 views
0

나는 org.xhtmlrenderer.pdf.ITextRenderer 클래스를 사용하여 HTML 파일에서 PDF를 생성하기 위해 IText와 함께 Flying Saucer를 사용하고 있습니다. 내 코드는 간단합니다. 생성 된 코드는 그래서 같은 방식으로 캡슐화 :FlyingSaucer ITextRenderer 완료 오류 (불균형 저장/복원 및 빈 PDF 파일)

/* PDfGenerator class only has ONE instance */ 
public PdfGenerator() { 
    this.renderer = new ITextRenderer(); //This is a class variable that only gets instantiated ONCE 
} 

public void generatePDF(String outputFilePath, String htmlContent) { 
    renderer.setDocumentFromString(htmlContent); 
    renderer.layout(); 
    renderer.createPDF(new BufferedOutputStream(
      new FileOutputStream(new File(outputFilePath)), BUFFER_SIZE), true); 
    renderer.finishPDF(); 
} 

편집 :

내 생성기 클래스가 실제로 단일 개체로 스프링에 의해 관리됩니다. 나는 PDF 생성 작업을위한 대기열 역할을하는 ExecutorService를 가진 관리자 클래스를 가지고있다. 이 관리자는 싱글 톤 생성기를 사용하여 객체를 생성합니다. 따라서 ITextRenderer를 한 번만 인스턴스화하고 다시 사용합니다. 이제 최대 2 개의 스레드를 동시에 작동하도록 대기열을 설정했습니다. 두 개의 스레드가 하나의 렌더러를 사용하여 두 개의 개별 PDF 세트를 렌더링하는 상황이 발생하기 때문에 이것이 아마도 원인 일지를 깨달았습니다.

이제 실제로 렌더링 당 두 번 "마무리"라고 부르는 것을 깨달았습니다! createPDF() 오류 호출 중 하나 (두 번째 매개 변수로 true 전달) 및 finishPDF()에 대한 하나의 명시 적 호출.

이것은 꽤 오랫동안 실행되어 왔으며 PDF를 성공적으로 생성 할 수있었습니다. 입니다. 나는 두 종류의 에러를 산발적으로 만나고있다 :

  1. 불균형 저장/복원 상태 연산자 때문에 런타임 예외가 발생했다. 샘플 스택 트레이스는 다음과 같이

    java.lang.RuntimeException: Unbalanced save/restore state operators. 
    at com.lowagie.text.pdf.PdfContentByte.restoreState(Unknown Source) ~[itext-2.0.8.jar:na] 
    at org.xhtmlrenderer.pdf.ITextOutputDevice.setClip(ITextOutputDevice.java:737) ~[core-renderer-R8.jar:na] 
    at org.xhtmlrenderer.pdf.ITextRenderer.paintPage(ITextRenderer.java:387) ~[core-renderer-R8.jar:na] 
    at org.xhtmlrenderer.pdf.ITextRenderer.writePDF(ITextRenderer.java:348) ~[core-renderer-R8.jar:na] 
    at org.xhtmlrenderer.pdf.ITextRenderer.createPDF(ITextRenderer.java:315) ~[core-renderer-R8.jar:na] 
    at org.xhtmlrenderer.pdf.ITextRenderer.createPDF(ITextRenderer.java:280) ~[core-renderer-R8.jar:na] 
    
  2. PDF로는 최악의/변형 섹션이나, 빈 페이지를이 빠져 생성.

제 2 판에서는 finishPDF()를 두 번 호출해야 할 것으로 확신합니다. 그러나 1 호에서는 이 발생하기 전에 finishPDF() 호출이 실행되므로 문제의 원인인지는 실제로 알 수 없습니다.

Flying Saucer를 iText와 함께 사용하면서이 두 가지 문제를 경험 한 경험이 있습니까?

+0

전체 FS 코드를 게시 할 수 있습니까? 예 : 여기서 문서를 설정합니다. 2 : CSS, pagebreaktags 등을 사용합니까? 이 때로는 빈 페이지가 표시 될 수 있습니다. 파일 끝에 빈 줄이 있거나 그림의 공간이 충분하지 않은 것일 수 있습니다. – ollo

+1

Btw. 'finishPDF()'호출을 제거하면 어떻게됩니까?'finish = true' 매개 변수를 가진'createPDF'는 (당신이 설정 한대로) 두 번째 마무리가 필요하지 않습니다 (하지만 부정적인 방식으로 pdf에 영향을주지 않아야합니다). – ollo

+0

안녕하세요 @ollo, 질문에 대한 자세한 내용을 추가했습니다. 또한 실제로 렌더러의 인스턴스 하나에 동시에 액세스하는 중임을 알았습니다. 이는 위에서 언급 한 문제가 발생할 수있는 이유 일 수 있습니다. 원래 렌더러 초기화 시간이 너무 비쌌다 고 생각했기 때문에 원래 이런 식으로 디자인했습니다 ... 새로운 렌더러 인스턴스를 생성하여 동시 PDF 생성 대기열을 조작 할 수있는 것이 더 나은지 궁금합니다. 나는 접선을했다. 어쨌든 내 결과를 확인할 수 있니? :) –

답변

1

내가 겪은 문제는 기본적으로 같은 ITextRenderer 인스턴스를 다른 스레드에서 동시에 액세스하므로 현재 실행중인 PDF 생성 작업의 처리가 엉망입니다.

저는 Executor 서비스가 단지 하나의 쓰레드를 사용하고 생성 작업을 순차적으로 만들었고, 제 견해에 따라 한 번에 하나씩 처리하는 한 동일한 ITextRenderer를 재사용 할 수 있습니다.

Flying Saucer lib의 개발자에게이 질문을 보내 드렸습니다. 회신 할 때이 게시물을 업데이트 할 것입니다.

1 개의 스레드와 1 개의 사전 인스턴스화 된 ITextRenderer 인스턴스를 사용하여 생성하거나 여러 스레드를 사용하지만 스레드 당 ITextRenderer를 인스턴스화하는 것이 더 효율적인지 알아 내야합니다.

+1

PDF 생성마다 ITextRenderer를 인스턴스화한다고 생각 해본 적이 있습니까? 나는 장황한 ITextRenderers가 메모리 부족 오류를 일으키는 '컨텍스트'에 최대 32 개의 이미지를 캐싱하고 있음을 발견했습니다. –

+0

@AnthonyChuinard 이것은 실제로 매우 유용한 정보입니다 ... 최근에 내 앱에서도 일부 OOM 오류가 발생했습니다. 감사. –