1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.exoplatform.services.pdfviewer;
18
19 import java.io.BufferedInputStream;
20 import java.io.BufferedOutputStream;
21 import java.io.File;
22 import java.io.FileInputStream;
23 import java.io.FileOutputStream;
24 import java.io.InputStream;
25 import java.io.OutputStream;
26 import java.io.Serializable;
27 import java.util.logging.Level;
28 import java.util.logging.Logger;
29
30 import javax.jcr.Node;
31
32 import org.apache.commons.lang.StringUtils;
33 import org.artofsolving.jodconverter.office.OfficeException;
34 import org.exoplatform.container.xml.InitParams;
35 import org.exoplatform.container.xml.ValueParam;
36 import org.exoplatform.services.cache.CacheService;
37 import org.exoplatform.services.cache.ExoCache;
38 import org.exoplatform.services.cms.impl.Utils;
39 import org.exoplatform.services.cms.jodconverter.JodConverterService;
40 import org.exoplatform.services.cms.mimetype.DMSMimeTypeResolver;
41 import org.exoplatform.services.jcr.RepositoryService;
42 import org.exoplatform.services.log.ExoLogger;
43 import org.exoplatform.services.log.Log;
44 import org.icepdf.core.pobjects.Document;
45
46
47
48
49
50
51 public class PDFViewerService {
52 private static final Log LOG = ExoLogger.getLogger(PDFViewerService.class.getName());
53
54 private static final int MAX_NAME_LENGTH = 150;
55
56 public static final long DEFAULT_MAX_FILE_SIZE = 10 * 1024 * 1024;
57
58 public static final long DEFAULT_MAX_PAGES = 99;
59
60 public static final String MAX_FILE_SIZE_PARAM_NAME = "maxFileSize";
61
62 public static final String MAX_PAGES_PARAM_NAME = "maxPages";
63
64 private static final String CACHE_NAME = "ecms.PDFViewerService";
65
66 private JodConverterService jodConverter_;
67
68 private ExoCache<Serializable, Object> pdfCache;
69
70 private long maxFileSize;
71
72 private long maxPages;
73
74 public PDFViewerService(RepositoryService repositoryService,
75 CacheService caService,
76 JodConverterService jodConverter,
77 InitParams initParams) throws Exception {
78 jodConverter_ = jodConverter;
79 pdfCache = caService.getCacheInstance(CACHE_NAME);
80
81 maxFileSize = DEFAULT_MAX_FILE_SIZE;
82 maxPages = DEFAULT_MAX_PAGES;
83 if (initParams != null) {
84 ValueParam maxFileSizeValueParam = initParams.getValueParam(MAX_FILE_SIZE_PARAM_NAME);
85 if (maxFileSizeValueParam != null) {
86 try {
87 maxFileSize = Long.parseLong(maxFileSizeValueParam.getValue()) * 1024 * 1024;
88 } catch (NumberFormatException e) {
89 LOG.warn("Parameter " + MAX_FILE_SIZE_PARAM_NAME + " for document preview is not a valid number ("
90 + maxFileSizeValueParam.getValue() + "), default value will be used (" + DEFAULT_MAX_FILE_SIZE + ")");
91 }
92 }
93 ValueParam maxPagesValueParam = initParams.getValueParam(MAX_PAGES_PARAM_NAME);
94 if (maxPagesValueParam != null) {
95 try {
96 maxPages = Long.parseLong(maxPagesValueParam.getValue());
97 } catch (NumberFormatException e) {
98 LOG.warn("Parameter " + MAX_PAGES_PARAM_NAME + " for document preview is not a valid number ("
99 + maxPagesValueParam.getValue() + "), default value will be used (" + MAX_PAGES_PARAM_NAME + ")");
100 }
101 }
102 }
103 }
104
105 public long getMaxFileSize() {
106 return maxFileSize;
107 }
108
109 public long getMaxPages() {
110 return maxPages;
111 }
112
113 public ExoCache<Serializable, Object> getCache() {
114 return pdfCache;
115 }
116
117
118
119
120
121
122
123
124
125 public Document initDocument(Node currentNode, String repoName) throws Exception {
126 return buildDocumentImage(getPDFDocumentFile(currentNode, repoName), currentNode.getName());
127 }
128
129 public Document buildDocumentImage(File input, String name) {
130 Document document = new Document();
131
132
133
134
135
136 Logger.getLogger(Document.class.toString()).setLevel(Level.OFF);
137
138 if (input == null)
139 return null;
140
141
142 try {
143
144
145 name = reduceFileNameSize(name);
146 FileInputStream fis = new FileInputStream(input);
147 document.setInputStream(new BufferedInputStream(fis), name);
148 return document;
149 } catch (Exception ex) {
150 LOG.warn("Failed to build Document image from pdf file " + name);
151 if (LOG.isDebugEnabled()) {
152 LOG.debug(ex);
153 }
154 return null;
155 }
156 }
157
158
159
160
161
162
163
164
165
166 public File getPDFDocumentFile(Node currentNode, String repoName) throws Exception {
167 String wsName = currentNode.getSession().getWorkspace().getName();
168 String uuid = currentNode.getUUID();
169 StringBuilder bd = new StringBuilder();
170 StringBuilder bd1 = new StringBuilder();
171 StringBuilder bd2 = new StringBuilder();
172 bd.append(repoName).append("/").append(wsName).append("/").append(uuid);
173 bd1.append(bd).append("/jcr:lastModified");
174 bd2.append(bd).append("/jcr:baseVersion");
175 String path = (String) pdfCache.get(new ObjectKey(bd.toString()));
176 String lastModifiedTime = (String) pdfCache.get(new ObjectKey(bd1.toString()));
177 String cachedBaseVersion = (String) pdfCache.get(new ObjectKey(bd2.toString()));
178 File content = null;
179 String name = currentNode.getName().replaceAll(":", "_");
180 Node contentNode = currentNode.getNode("jcr:content");
181
182 String lastModified = Utils.getJcrContentLastModified(currentNode);
183 String baseVersion = Utils.getJcrContentBaseVersion(currentNode);
184 if (path == null || !(content = new File(path)).exists() || !lastModified.equals(lastModifiedTime) ||
185 !StringUtils.equals(baseVersion, cachedBaseVersion)) {
186 String mimeType = contentNode.getProperty("jcr:mimeType").getString();
187 InputStream input = new BufferedInputStream(contentNode.getProperty("jcr:data").getStream());
188
189 if (name.indexOf(".") > 0)
190 name = name.substring(0, name.lastIndexOf("."));
191
192
193 name = reduceFileNameSize(name);
194 content = File.createTempFile(name + "_tmp", ".pdf");
195
196
197 String extension = DMSMimeTypeResolver.getInstance().getExtension(mimeType);
198 if ("pdf".equals(extension)) {
199 read(input, new BufferedOutputStream(new FileOutputStream(content)));
200 } else {
201
202 File in = File.createTempFile(name + "_tmp", "." + extension);
203 read(input, new BufferedOutputStream(new FileOutputStream(in)));
204 long fileSize = in.length();
205 if (LOG.isDebugEnabled()) {
206 LOG.debug("File '" + currentNode.getPath() + "' of " + fileSize + " B. Size limit for preview: "
207 + (getMaxFileSize() / (1024 * 1024)) + " MB");
208 }
209 if (fileSize <= getMaxFileSize()) {
210 try {
211 boolean success = jodConverter_.convert(in, content, "pdf");
212
213
214 if (!success) {
215 content.delete();
216 content = null;
217 }
218
219 } catch (OfficeException connection) {
220 content.delete();
221 content = null;
222 if (LOG.isErrorEnabled()) {
223 LOG.error("Exception when using Office Service", connection);
224 }
225 } finally {
226 in.delete();
227 }
228 } else {
229 LOG.info("File '" + currentNode.getPath() + "' is too big for preview.");
230 content.delete();
231 content = null;
232 in.delete();
233 }
234 }
235 if (content != null && content.exists()) {
236 if (contentNode.hasProperty("jcr:lastModified")) {
237 pdfCache.put(new ObjectKey(bd.toString()), content.getPath());
238 pdfCache.put(new ObjectKey(bd1.toString()), lastModified);
239 }
240 pdfCache.put(new ObjectKey(bd2.toString()), baseVersion);
241 }
242 }
243 return content;
244 }
245
246
247
248
249
250
251
252
253 private String reduceFileNameSize(String name) {
254 return (name != null && name.length() > MAX_NAME_LENGTH) ? name.substring(0, MAX_NAME_LENGTH) : name;
255 }
256
257 private void read(InputStream is, OutputStream os) throws Exception {
258 int bufferLength = 1024;
259 int readLength = 0;
260 while (readLength > -1) {
261 byte[] chunk = new byte[bufferLength];
262 readLength = is.read(chunk);
263 if (readLength > 0) {
264 os.write(chunk, 0, readLength);
265 }
266 }
267 os.flush();
268 os.close();
269 }
270 }