File Source: pdfview.java
/*
P/P * Method: void net.sourceforge.pebble.web.view.PdfView$1(PdfView)
*/
1 /*
2 * Copyright (c) 2003-2006, Simon Brown
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * - Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 *
16 * - Neither the name of Pebble nor the names of its contributors may
17 * be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32 package net.sourceforge.pebble.web.view;
33
34 import java.io.ByteArrayInputStream;
35 import java.io.BufferedOutputStream;
36 import java.io.IOException;
37 import java.io.File;
38 import java.io.FilenameFilter;
39
40 import org.xml.sax.InputSource;
41 import org.xml.sax.SAXException;
42
43 import org.w3c.dom.Document;
44
45 import javax.xml.parsers.DocumentBuilder;
46 import javax.xml.parsers.DocumentBuilderFactory;
47 import javax.xml.parsers.ParserConfigurationException;
48
49 import net.sourceforge.pebble.PebbleContext;
50 import net.sourceforge.pebble.domain.Tag;
51 import net.sourceforge.pebble.domain.BlogEntry;
52 import net.sourceforge.pebble.util.StringUtils;
53 import net.sourceforge.pebble.web.listener.PebblePDFCreationListener;
54
/*
P/P * Method: void net.sourceforge.pebble.web.view.PdfView(BlogEntry, String)
*
* Postconditions:
* this.entry == entry
* init'ed(this.entry)
* this.filename == filename
* init'ed(this.filename)
* this.length == 0
*/
55 import javax.servlet.ServletContext;
56 import javax.servlet.ServletException;
57 import javax.servlet.http.HttpServletRequest;
58 import javax.servlet.http.HttpServletResponse;
59
60 import java.util.Iterator;
61
62 import org.apache.commons.logging.Log;
63 import org.apache.commons.logging.LogFactory;
64
65 import com.lowagie.text.pdf.PdfWriter;
66 import com.lowagie.text.pdf.BaseFont;
67 import com.lowagie.text.DocumentException;
68
69 import org.xhtmlrenderer.pdf.ITextRenderer;
70 import org.xhtmlrenderer.pdf.TrueTypeUtil;
71
72
73 /**
74 * Represents a binary view component and prepares the model for display.
75 *
76 * @author Alexander Zagniotov
77 */
78 public class PdfView extends BinaryView {
79
80
81 private static Log log = LogFactory.getLog(PdfView.class);
82
83 private static final String SEP = "/";
84 private static final String FONTS_PATH = "fonts";
85 private static final String THEMES_PATH = "themes";
86 private static final String DEFAULT_ENCODING = "UTF-8";
87 private static final String PDF_CSS = "pdf.css";
88 private static final String SYSTEM_THEME_PATH = HtmlView.SYSTEM_THEME;
89
90 private String filename = "default.pdf";
91 private BlogEntry entry;
92 private long length = 0;
93
94 public PdfView(BlogEntry entry, String filename) {
95 this.entry = entry;
96 this.filename = filename;
97 }
98
99 /**
100 * Gets the title of this view.
101 *
102 * @return the title as a String
103 */
/*
P/P * Method: String getContentType()
*
* Postconditions:
* return_value == &"application.pdf"
*/
104 public String getContentType() {
105 return "application/pdf";
106 }
107
/*
P/P * Method: long getContentLength()
*
* Preconditions:
* init'ed(this.length)
*
* Postconditions:
* return_value == this.length
* init'ed(return_value)
*/
108 public long getContentLength() {
109 return length;
110 }
111
112 /**
113 * Dispatches this view.
114 *
115 * @param request the HttpServletRequest instance
116 * @param response the HttpServletResponse instance
117 * @param context
118 */
119 public void dispatch(HttpServletRequest request, HttpServletResponse response, ServletContext context) throws ServletException {
120
121 try {
/*
P/P * Method: void dispatch(HttpServletRequest, HttpServletResponse, ServletContext)
*
* Preconditions:
* log != null
* (soft) init'ed(net.sourceforge.pebble.PebbleContext__static_init.new PebbleContext(PebbleContext__static_init#1).webApplicationRoot)
* (soft) net/sourceforge/pebble/web/listener/PebblePDFCreationListener.log != null
* (soft) response != null
* (soft) this.entry != null
* (soft) init'ed(this.filename)
*
* Presumptions:
* files[0]@187 != null
* java.io.File:listFiles(...)@187 != null
* java.util.Iterator:next(...)@157 != null
* javax.xml.parsers.DocumentBuilder:parse(...)@234 != null
* javax.xml.parsers.DocumentBuilderFactory:newDocumentBuilder(...)@232 != null
* ...
*
* Test Vectors:
* files.length@187: {0}, {1..+Inf}
* java.io.File:isDirectory(...)@186: {0}, {1}
* java.lang.String:equals(...)@158: {1}, {0}
* java.lang.String:equals(...)@206: {1}, {0}
* java.util.Iterator:hasNext(...)@156: {1}, {0}
* java.util.Iterator:hasNext(...)@160: {0}, {1}
*/
122 ITextRenderer renderer = new ITextRenderer();
123
124 //This will be an attachment
125 response.setHeader("Content-Disposition", "attachment; filename=" + filename);
126 response.setHeader("Expires", "0");
127 response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
128 response.setHeader("Pragma", "public");
129
130 String author = entry.getUser().getName();
131 String title = entry.getTitle();
132 String subtitle = entry.getSubtitle();
133 String body = entry.getBody();
134 String blogName = entry.getBlog().getName();
135 String entryPermalink = entry.getPermalink();
136 String entryDescription = entry.getBlog().getDescription();
137
138 //Some of the HTML entities need to be escaped to Unicode notation \\uXXXX for XHTML markup to validate
139 title = StringUtils.transformHTML(title);
140 subtitle = StringUtils.transformHTML(subtitle);
141 body = StringUtils.unescapeHTMLEntities(body);
142
143 //Build absolute path to: <pebble_root>/themes/_pebble/fonts/
144 String webApplicationRoot = PebbleContext.getInstance().getWebApplicationRoot() + SEP + THEMES_PATH;
145
146 //<pebble_root> + / + themes + / + _pebble + / + fonts
147 String fontDirAbsolutePath = webApplicationRoot + SEP + SYSTEM_THEME_PATH + SEP + FONTS_PATH;
148 File fontDir = new File(fontDirAbsolutePath);
149
150
151 //Get blog entry tags for PDF metadata 'keywords'
152 StringBuffer tags = new StringBuffer();
153 Iterator<Tag> currentEntryTags = entry.getAllTags().iterator();
154
155 //Build a string out of blog entry tags and seperate them by comma
156 while (currentEntryTags.hasNext()) {
157 Tag currentTag = currentEntryTags.next();
158 if (currentTag.getName() != null && !currentTag.getName().equals("")) {
159 tags.append(currentTag.getName());
160 if (currentEntryTags.hasNext()) {
161 tags.append(",");
162 }
163 }
164 }
165
166 //Build valid XHTML source from blog entry for parsing
167 StringBuffer buf = new StringBuffer();
168 buf.append("<html>");
169 buf.append("<head>");
170 buf.append("<meta name=\"title\" content=\"" + title + " - " + blogName + "\"/>");
171 buf.append("<meta name=\"subject\" content=\"" + title + "\"/>");
172 buf.append("<meta name=\"keywords\" content=\"" + tags.toString().trim() + "\"/>");
173 buf.append("<meta name=\"author\" content=\"" + author + "\"/>");
174 buf.append("<meta name=\"creator\" content=\"Pebble (by pebble.sourceforge.net)\"/>");
175 buf.append("<meta name=\"producer\" content=\"Flying Saucer (by xhtmlrenderer.dev.java.net)\"/>");
176 buf.append("<link rel='stylesheet' type='text/css' href='" + entry.getBlog().getUrl() +
177 THEMES_PATH + SEP +
178 SYSTEM_THEME_PATH + SEP +
179 PDF_CSS + "' media='print' />");
180 buf.append("</head>");
181 buf.append("<body>");
182 buf.append("<div id=\"header\" style=\"\">" + blogName + " - " + entryDescription + "</div>");
183 buf.append("<p>");
184
185 //Gets TTF or OTF font file from the font directory in the system theme folder
186 if (fontDir.isDirectory()) {
187 File[] files = fontDir.listFiles(new FilenameFilter() {
188 public boolean accept(File dir, String name) {
/*
P/P * Method: bool accept(File, String)
*
* Preconditions:
* name != null
*
* Postconditions:
* init'ed(return_value)
*
* Test Vectors:
* java.lang.String:endsWith(...)@192: {1}, {0}
*/
189 String lower = name.toLowerCase();
190
191 //Load TTF or OTF files
192 return lower.endsWith(".otf") || lower.endsWith(".ttf");
193 }
194 });
195
196 if (files.length > 0) {
+ 197 String fontFamilyName = "";
198 //You should always embed TrueType fonts.
199 renderer.getFontResolver().addFont(files[0].getAbsolutePath(), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
200 log.info("Added font: " + files[0].getAbsolutePath());
201
202 //Get font family name from the BaseFont object. All this work just to get font family name
203 BaseFont font = BaseFont.createFont(files[0].getAbsolutePath(), BaseFont.IDENTITY_H , BaseFont.NOT_EMBEDDED);
204 fontFamilyName = TrueTypeUtil.getFamilyName(font);
205
206 if (!fontFamilyName.equals("")) {
207 //Wrap DIV with font family name around the content of the blog entry
208 author = "<div style=\"font-family: " + fontFamilyName + ";\">" + author + "</div>";
209 title = "<div style=\"font-family: " + fontFamilyName + ";\">" + title + "</div>";
210 subtitle = "<div style=\"font-family: " + fontFamilyName + ";\">" + subtitle + "</div>";
211 body = "<div style=\"font-family: " + fontFamilyName + ";\">" + body + "</div>";
212 log.info("PDFGenerator - Added font family: '" + fontFamilyName + "' to PDF content");
213 }
214 }
215 }
216
217 buf.append("<h1>" + title + "</h1>");
218 buf.append("<h2>" + subtitle + "</h2>");
219 buf.append("</p>");
220 buf.append("<p>" + body + "</p>");
221 buf.append("<p><br /><br /><br />");
222 buf.append("<i>Published by " + author + "</i><br />");
223 buf.append("<i>" + entry.getDate().toString() + "</i><br />");
224 buf.append("<i><a href=\"" + entryPermalink + "\" title=\"" + entryPermalink + "\">" + entryPermalink + "</a></i>");
225 buf.append("</p>");
226 buf.append("</body>");
227 buf.append("</html>");
228
229 byte[] bytes = buf.toString().getBytes(DEFAULT_ENCODING);
230
231 ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
232 DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
233 InputSource is = new InputSource(bais);
234 Document doc = builder.parse(is);
235
236 //Listener that will parse HTML header meta tags, and will set them to PDF document as meta data
237 PebblePDFCreationListener pdfListener = new PebblePDFCreationListener();
238 pdfListener.parseMetaTags(doc);
239 renderer.setListener(pdfListener);
240 renderer.setDocument(doc, null);
241 renderer.layout();
242
243 BufferedOutputStream bufferedOutput = new BufferedOutputStream(response.getOutputStream());
244
245 renderer.createPDF(bufferedOutput);
246 bufferedOutput.flush();
247 bufferedOutput.close();
248
249 log.info("Successfully generated PDF document: " + filename);
250 }
251
252 catch (ParserConfigurationException e) {
253 log.error("Could not create PDF, could not get new instance of DocumentBuilder: " + e);
254 }
255
256 catch (SAXException e) {
257 log.error("Could not create PDF, could not parse InputSource: " + e);
258 }
259
260 catch (IOException e) {
261 log.error("Could not create PDF: " + e);
262 }
263
264 catch (DocumentException e) {
265 log.error("iText could not create PDF document: " + e);
266 }
267
268 catch (Exception e) {
269 log.error("Could not create PDF: " + e);
270 }
271 }
272 }
SofCheck Inspector Build Version : 2.22510
| pdfview.java |
2010-Jun-25 19:40:32 |
| pdfview.class |
2010-Jul-19 20:23:38 |
| pdfview$1.class |
2010-Jul-19 20:23:38 |