1 /*
2 * Copyright 2002-2008 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.springframework.web.servlet.view.document;
18
19 import java.io.ByteArrayOutputStream;
20 import java.io.OutputStream;
21 import java.util.Map;
22
23 import javax.servlet.http.HttpServletRequest;
24 import javax.servlet.http.HttpServletResponse;
25
26 import com.lowagie.text.Document;
27 import com.lowagie.text.DocumentException;
28 import com.lowagie.text.PageSize;
29 import com.lowagie.text.pdf.PdfWriter;
30
31 import org.springframework.web.servlet.view.AbstractView;
32
33 /**
34 * Abstract superclass for PDF views, using Bruno Lowagie's
35 * <a href="http://www.lowagie.com/iText">iText</a> package.
36 * Application-specific view classes will extend this class.
37 * The view will be held in the subclass itself, not in a template.
38 *
39 * <p>Note: Internet Explorer requires a ".pdf" extension, as
40 * it doesn't always respect the declared content type.
41 *
42 * @author Rod Johnson
43 * @author Juergen Hoeller
44 * @author Jean-Pierre Pawlak
45 * @see AbstractPdfStamperView
46 */
47 public abstract class AbstractPdfView extends AbstractView {
48
49 /**
50 * This constructor sets the appropriate content type "application/pdf".
51 * Note that IE won't take much notice of this, but there's not a lot we
52 * can do about this. Generated documents should have a ".pdf" extension.
53 */
54 public AbstractPdfView() {
55 setContentType("application/pdf");
56 }
57
58
59 protected boolean generatesDownloadContent() {
60 return true;
61 }
62
63 protected final void renderMergedOutputModel(
64 Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {
65
66 // IE workaround: write into byte array first.
67 ByteArrayOutputStream baos = createTemporaryOutputStream();
68
69 // Apply preferences and build metadata.
70 Document document = newDocument();
71 PdfWriter writer = newWriter(document, baos);
72 prepareWriter(model, writer, request);
73 buildPdfMetadata(model, document, request);
74
75 // Build PDF document.
76 document.open();
77 buildPdfDocument(model, document, writer, request, response);
78 document.close();
79
80 // Flush to HTTP response.
81 writeToResponse(response, baos);
82 }
83
84 /**
85 * Create a new document to hold the PDF contents.
86 * <p>By default returns an A4 document, but the subclass can specify any
87 * Document, possibly parameterized via bean properties defined on the View.
88 * @return the newly created iText Document instance
89 * @see com.lowagie.text.Document#Document(com.lowagie.text.Rectangle)
90 */
91 protected Document newDocument() {
92 return new Document(PageSize.A4);
93 }
94
95 /**
96 * Create a new PdfWriter for the given iText Document.
97 * @param document the iText Document to create a writer for
98 * @param os the OutputStream to write to
99 * @return the PdfWriter instance to use
100 * @throws DocumentException if thrown during writer creation
101 */
102 protected PdfWriter newWriter(Document document, OutputStream os) throws DocumentException {
103 return PdfWriter.getInstance(document, os);
104 }
105
106 /**
107 * Prepare the given PdfWriter. Called before building the PDF document,
108 * that is, before the call to <code>Document.open()</code>.
109 * <p>Useful for registering a page event listener, for example.
110 * The default implementation sets the viewer preferences as returned
111 * by this class's <code>getViewerPreferences()</code> method.
112 * @param model the model, in case meta information must be populated from it
113 * @param writer the PdfWriter to prepare
114 * @param request in case we need locale etc. Shouldn't look at attributes.
115 * @throws DocumentException if thrown during writer preparation
116 * @see com.lowagie.text.Document#open()
117 * @see com.lowagie.text.pdf.PdfWriter#setPageEvent
118 * @see com.lowagie.text.pdf.PdfWriter#setViewerPreferences
119 * @see #getViewerPreferences()
120 */
121 protected void prepareWriter(Map model, PdfWriter writer, HttpServletRequest request)
122 throws DocumentException {
123
124 writer.setViewerPreferences(getViewerPreferences());
125 }
126
127 /**
128 * Return the viewer preferences for the PDF file.
129 * <p>By default returns <code>AllowPrinting</code> and
130 * <code>PageLayoutSinglePage</code>, but can be subclassed.
131 * The subclass can either have fixed preferences or retrieve
132 * them from bean properties defined on the View.
133 * @return an int containing the bits information against PdfWriter definitions
134 * @see com.lowagie.text.pdf.PdfWriter#AllowPrinting
135 * @see com.lowagie.text.pdf.PdfWriter#PageLayoutSinglePage
136 */
137 protected int getViewerPreferences() {
138 return PdfWriter.AllowPrinting | PdfWriter.PageLayoutSinglePage;
139 }
140
141 /**
142 * Populate the iText Document's meta fields (author, title, etc.).
143 * <br>Default is an empty implementation. Subclasses may override this method
144 * to add meta fields such as title, subject, author, creator, keywords, etc.
145 * This method is called after assigning a PdfWriter to the Document and
146 * before calling <code>document.open()</code>.
147 * @param model the model, in case meta information must be populated from it
148 * @param document the iText document being populated
149 * @param request in case we need locale etc. Shouldn't look at attributes.
150 * @see com.lowagie.text.Document#addTitle
151 * @see com.lowagie.text.Document#addSubject
152 * @see com.lowagie.text.Document#addKeywords
153 * @see com.lowagie.text.Document#addAuthor
154 * @see com.lowagie.text.Document#addCreator
155 * @see com.lowagie.text.Document#addProducer
156 * @see com.lowagie.text.Document#addCreationDate
157 * @see com.lowagie.text.Document#addHeader
158 */
159 protected void buildPdfMetadata(Map model, Document document, HttpServletRequest request) {
160 }
161
162 /**
163 * Subclasses must implement this method to build an iText PDF document,
164 * given the model. Called between <code>Document.open()</code> and
165 * <code>Document.close()</code> calls.
166 * <p>Note that the passed-in HTTP response is just supposed to be used
167 * for setting cookies or other HTTP headers. The built PDF document itself
168 * will automatically get written to the response after this method returns.
169 * @param model the model Map
170 * @param document the iText Document to add elements to
171 * @param writer the PdfWriter to use
172 * @param request in case we need locale etc. Shouldn't look at attributes.
173 * @param response in case we need to set cookies. Shouldn't write to it.
174 * @throws Exception any exception that occured during document building
175 * @see com.lowagie.text.Document#open()
176 * @see com.lowagie.text.Document#close()
177 */
178 protected abstract void buildPdfDocument(
179 Map model, Document document, PdfWriter writer,
180 HttpServletRequest request, HttpServletResponse response)
181 throws Exception;
182
183 }