1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.exoplatform.ecm.webui.viewer;
18
19 import org.exoplatform.download.DownloadService;
20 import org.exoplatform.download.InputStreamDownloadResource;
21 import org.exoplatform.portal.webui.util.Util;
22 import org.exoplatform.portal.webui.workspace.UIPortalApplication;
23 import org.exoplatform.services.cms.mimetype.DMSMimeTypeResolver;
24 import org.exoplatform.services.log.ExoLogger;
25 import org.exoplatform.services.log.Log;
26 import org.exoplatform.services.pdfviewer.PDFViewerService;
27 import org.exoplatform.services.resources.ResourceBundleService;
28 import org.exoplatform.services.wcm.utils.WCMCoreUtils;
29 import org.exoplatform.web.application.RequireJS;
30 import org.exoplatform.webui.application.portlet.PortletRequestContext;
31 import org.exoplatform.webui.config.annotation.ComponentConfig;
32 import org.exoplatform.webui.config.annotation.EventConfig;
33 import org.exoplatform.webui.core.UIComponent;
34 import org.exoplatform.webui.core.lifecycle.UIFormLifecycle;
35 import org.exoplatform.webui.core.model.SelectItemOption;
36 import org.exoplatform.webui.event.Event;
37 import org.exoplatform.webui.event.Event.Phase;
38 import org.exoplatform.webui.event.EventListener;
39 import org.exoplatform.webui.form.UIForm;
40 import org.exoplatform.webui.form.UIFormSelectBox;
41 import org.exoplatform.webui.form.UIFormStringInput;
42 import org.icepdf.core.pobjects.Document;
43 import org.icepdf.core.pobjects.PInfo;
44
45 import javax.jcr.Node;
46 import javax.jcr.NodeIterator;
47 import javax.jcr.RepositoryException;
48 import javax.portlet.PortletRequest;
49 import java.io.BufferedInputStream;
50 import java.io.File;
51 import java.io.FileInputStream;
52 import java.lang.reflect.InvocationTargetException;
53 import java.lang.reflect.Method;
54 import java.util.ArrayList;
55 import java.util.HashMap;
56 import java.util.List;
57 import java.util.Locale;
58 import java.util.Map;
59 import java.util.MissingResourceException;
60 import java.util.ResourceBundle;
61
62
63
64
65
66
67
68
69 @ComponentConfig(
70 lifecycle = UIFormLifecycle.class,
71 template = "classpath:resources/templates/PDFJSViewer.gtmpl",
72 events = {
73 @EventConfig(listeners = PDFViewer.NextPageActionListener.class, phase = Phase.DECODE),
74 @EventConfig(listeners = PDFViewer.PreviousPageActionListener.class, phase = Phase.DECODE),
75 @EventConfig(listeners = PDFViewer.GotoPageActionListener.class, phase = Phase.DECODE),
76 @EventConfig(listeners = PDFViewer.RotateRightPageActionListener.class, phase = Phase.DECODE),
77 @EventConfig(listeners = PDFViewer.RotateLeftPageActionListener.class, phase = Phase.DECODE),
78 @EventConfig(listeners = PDFViewer.ScalePageActionListener.class, phase = Phase.DECODE),
79 @EventConfig(listeners = PDFViewer.DownloadFileActionListener.class, phase = Phase.DECODE),
80 @EventConfig(listeners = PDFViewer.ZoomInPageActionListener.class, phase = Phase.DECODE),
81 @EventConfig(listeners = PDFViewer.ZoomOutPageActionListener.class, phase = Phase.DECODE)
82 }
83 )
84
85
86
87 public class PDFViewer extends UIForm {
88
89 private static final Log LOG = ExoLogger.getExoLogger(PDFViewer.class);
90
91 final static private String PAGE_NUMBER = "pageNumber";
92 final static private String SCALE_PAGE = "scalePage";
93 final private String localeFile = "locale.portlet.viewer.PDFViewer";
94 private String sharedResourcesBundleNames[];
95 private ResourceBundle sharedResourceBundle=null;
96 private static final int MIN_IE_SUPPORTED_BROWSER_VERSION = 9;
97 private static final int MIN_FF_SUPPORTED_BROWSER_VERSION = 20;
98 private static final int MIN_CHROME_SUPPORTED_BROWSER_VERSION = 20;
99
100 private int currentPageNumber_ = 1;
101 private int maximumOfPage_ = 0;
102 private float currentRotation_ = 0.0f;
103 private float currentScale_ = 1.0f;
104 private Map<String, String> metadatas = new HashMap<String, String>();
105
106 public PDFViewer() throws Exception {
107 addUIFormInput(new UIFormStringInput(PAGE_NUMBER, PAGE_NUMBER, "1"));
108 UIFormSelectBox uiScaleBox = new UIFormSelectBox(SCALE_PAGE, SCALE_PAGE, initScaleOptions());
109 uiScaleBox.setOnChange("ScalePage");
110 addUIFormInput(uiScaleBox);
111 uiScaleBox.setValue("1.0f");
112 }
113
114 public Method getMethod(UIComponent uiComponent, String name) throws NoSuchMethodException {
115 return uiComponent.getClass().getMethod(name, new Class[0]);
116 }
117
118 public void initDatas() throws Exception {
119 UIComponent uiParent = getParent();
120
121 Method method = getMethod(uiParent, "getOriginalNode");
122 Node originalNode = null;
123 if(method != null) originalNode = (Node) method.invoke(uiParent, (Object[]) null);
124
125 if(originalNode != null) {
126 Document document = getDocument(originalNode);
127 if (document != null) {
128 maximumOfPage_ = document.getNumberOfPages();
129 metadatas.clear();
130 putDocumentInfo(document.getInfo());
131 document.dispose();
132 } else maximumOfPage_ = -1;
133 }
134 }
135
136 public Map getMetadataExtraction() { return metadatas; }
137
138 public int getMaximumOfPage() throws Exception {
139 if(maximumOfPage_ == 0) {
140 initDatas();
141 }
142 return maximumOfPage_;
143 }
144
145 public float getCurrentRotation() { return currentRotation_; }
146
147 public void setRotation(float rotation) { currentRotation_ = rotation; }
148
149 public float getCurrentScale() { return currentScale_; }
150
151 public void setScale(float scale) { currentScale_ = scale; }
152
153 public int getPageNumber() { return currentPageNumber_; }
154
155 public void setPageNumber(int pageNum) { currentPageNumber_ = pageNum; };
156
157 public String getResourceBundle(String key) {
158 try {
159 Locale locale = Util.getUIPortal().getAncestorOfType(UIPortalApplication.class).getLocale();
160 ResourceBundleService resourceBundleService = WCMCoreUtils.getService(ResourceBundleService.class);
161 ResourceBundle resourceBundle = resourceBundleService.getResourceBundle(localeFile, locale, this.getClass().getClassLoader());
162
163 return resourceBundle.getString(key);
164 } catch (MissingResourceException e) {
165 return key;
166 }
167 }
168
169 public String getResource(String key) {
170 try {
171 Locale locale = Util.getUIPortal().getAncestorOfType(UIPortalApplication.class).getLocale();
172 ResourceBundleService resourceBundleService = WCMCoreUtils.getService(ResourceBundleService.class);
173 sharedResourcesBundleNames = resourceBundleService.getSharedResourceBundleNames();
174 sharedResourceBundle = resourceBundleService.getResourceBundle(sharedResourcesBundleNames, locale);
175
176 return sharedResourceBundle.getString(key);
177 } catch (MissingResourceException e) {
178 return key;
179 }
180 }
181
182 private Document getDocument(Node node) throws RepositoryException, Exception {
183 PDFViewerService pdfViewerService = getApplicationComponent(PDFViewerService.class);
184 String repository = (String) getMethod(this.getParent(), "getRepository").invoke(this.getParent(), (Object[]) null);
185 return pdfViewerService.initDocument(node, repository);
186 }
187
188 private void putDocumentInfo(PInfo documentInfo) {
189 if (documentInfo != null) {
190 if(documentInfo.getTitle() != null && documentInfo.getTitle().length() > 0) {
191 metadatas.put("title", documentInfo.getTitle());
192 }
193 if(documentInfo.getAuthor() != null && documentInfo.getAuthor().length() > 0) {
194 metadatas.put("author", documentInfo.getAuthor());
195 }
196 if(documentInfo.getSubject() != null && documentInfo.getSubject().length() > 0) {
197 metadatas.put("subject", documentInfo.getSubject());
198 }
199 if(documentInfo.getKeywords() != null && documentInfo.getKeywords().length() > 0) {
200 metadatas.put("keyWords", documentInfo.getKeywords());
201 }
202 if(documentInfo.getCreator() != null && documentInfo.getCreator().length() > 0) {
203 metadatas.put("creator", documentInfo.getCreator());
204 }
205 if(documentInfo.getProducer() != null && documentInfo.getProducer().length() > 0) {
206 metadatas.put("producer", documentInfo.getProducer());
207 }
208 try {
209 if(documentInfo.getCreationDate() != null) {
210 metadatas.put("creationDate", documentInfo.getCreationDate().toString());
211 }
212 } catch (Exception e) {
213 LOG.debug("Error when getting creation date.", e);
214 }
215 try {
216 if(documentInfo.getModDate() != null) {
217 metadatas.put("modDate", documentInfo.getModDate().toString());
218 }
219 } catch (Exception e) {
220 LOG.debug("Exception when getting modification date.", e);
221 }
222 }
223 }
224
225 private List<SelectItemOption<String>> initScaleOptions() {
226 List<SelectItemOption<String>> scaleOptions = new ArrayList<SelectItemOption<String>>();
227 scaleOptions.add(new SelectItemOption<String>("5%", "0.05f"));
228 scaleOptions.add(new SelectItemOption<String>("10%", "0.1f"));
229 scaleOptions.add(new SelectItemOption<String>("25%", "0.25f"));
230 scaleOptions.add(new SelectItemOption<String>("50%", "0.5f"));
231 scaleOptions.add(new SelectItemOption<String>("75%", "0.75f"));
232 scaleOptions.add(new SelectItemOption<String>("100%", "1.0f"));
233 scaleOptions.add(new SelectItemOption<String>("125%", "1.25f"));
234 scaleOptions.add(new SelectItemOption<String>("150%", "1.5f"));
235 scaleOptions.add(new SelectItemOption<String>("200%", "2.0f"));
236 scaleOptions.add(new SelectItemOption<String>("300%", "3.0f"));
237 return scaleOptions;
238 }
239
240
241
242
243
244 private boolean isNotModernBrowser() {
245 PortletRequestContext requestContext = PortletRequestContext.getCurrentInstance();
246 PortletRequest portletRequest = requestContext.getRequest();
247 String userAgent = portletRequest.getProperty("user-agent");
248 boolean isChrome = (userAgent.indexOf("Chrome/") != -1);
249 boolean isMSIE = (userAgent.indexOf("MSIE") != -1);
250 boolean isFirefox = (userAgent.indexOf("Firefox/") != -1);
251 String version = "1";
252 if (isFirefox) {
253
254 version = userAgent.replaceAll("^.*?Firefox/", "").replaceAll("\\.\\d+", "");
255 } else if (isChrome) {
256
257 version = userAgent.replaceAll("^.*?Chrome/(\\d+)\\..*$", "$1");
258 } else if (isMSIE) {
259
260 version = userAgent.replaceAll("^.*?MSIE\\s+(\\d+).*$", "$1");
261 }
262
263 boolean unsupportedBrowser = (isFirefox && Integer.parseInt(version) < MIN_FF_SUPPORTED_BROWSER_VERSION)
264 || (isChrome && Integer.parseInt(version) < MIN_CHROME_SUPPORTED_BROWSER_VERSION)
265 || (isMSIE && Integer.parseInt(version) < MIN_IE_SUPPORTED_BROWSER_VERSION);
266 return unsupportedBrowser;
267 }
268
269 static public class PreviousPageActionListener extends EventListener<PDFViewer> {
270 public void execute(Event<PDFViewer> event) throws Exception {
271 PDFViewer pdfViewer = event.getSource();
272 if(pdfViewer.currentPageNumber_ == 1) {
273 pdfViewer.getUIStringInput(PAGE_NUMBER).setValue(
274 Integer.toString((pdfViewer.currentPageNumber_)));
275 } else {
276 pdfViewer.getUIStringInput(PAGE_NUMBER).setValue(
277 Integer.toString((pdfViewer.currentPageNumber_ -1)));
278 pdfViewer.setPageNumber(pdfViewer.currentPageNumber_ - 1);
279 }
280 event.getRequestContext().addUIComponentToUpdateByAjax(pdfViewer);
281 }
282 }
283
284 static public class NextPageActionListener extends EventListener<PDFViewer> {
285 public void execute(Event<PDFViewer> event) throws Exception {
286 PDFViewer pdfViewer = event.getSource();
287 if(pdfViewer.currentPageNumber_ == pdfViewer.maximumOfPage_) {
288 pdfViewer.getUIStringInput(PAGE_NUMBER).setValue(
289 Integer.toString((pdfViewer.currentPageNumber_)));
290 } else {
291 pdfViewer.getUIStringInput(PAGE_NUMBER).setValue(
292 Integer.toString((pdfViewer.currentPageNumber_ + 1)));
293 pdfViewer.setPageNumber(pdfViewer.currentPageNumber_ + 1);
294 }
295 event.getRequestContext().addUIComponentToUpdateByAjax(pdfViewer);
296 }
297 }
298
299 static public class GotoPageActionListener extends EventListener<PDFViewer> {
300 public void execute(Event<PDFViewer> event) throws Exception {
301 PDFViewer pdfViewer = event.getSource();
302 String pageStr = pdfViewer.getUIStringInput(PAGE_NUMBER).getValue();
303 int pageNumber = 1;
304 try {
305 pageNumber = Integer.parseInt(pageStr);
306 } catch(NumberFormatException e) {
307 pageNumber = pdfViewer.currentPageNumber_;
308 }
309 if(pageNumber >= pdfViewer.maximumOfPage_) pageNumber = pdfViewer.maximumOfPage_;
310 else if(pageNumber < 1) pageNumber = 1;
311 pdfViewer.getUIStringInput(PAGE_NUMBER).setValue(Integer.toString((pageNumber)));
312 pdfViewer.setPageNumber(pageNumber);
313 event.getRequestContext().addUIComponentToUpdateByAjax(pdfViewer);
314 }
315 }
316
317 static public class RotateRightPageActionListener extends EventListener<PDFViewer> {
318 public void execute(Event<PDFViewer> event) throws Exception {
319 PDFViewer pdfViewer = event.getSource();
320 pdfViewer.setRotation(pdfViewer.currentRotation_ + 270.0f);
321 event.getRequestContext().addUIComponentToUpdateByAjax(pdfViewer);
322 }
323 }
324
325 static public class RotateLeftPageActionListener extends EventListener<PDFViewer> {
326 public void execute(Event<PDFViewer> event) throws Exception {
327 PDFViewer pdfViewer = event.getSource();
328 pdfViewer.setRotation(pdfViewer.currentRotation_ + 90.0f);
329 event.getRequestContext().addUIComponentToUpdateByAjax(pdfViewer);
330 }
331 }
332
333 static public class ScalePageActionListener extends EventListener<PDFViewer> {
334 public void execute(Event<PDFViewer> event) throws Exception {
335 PDFViewer pdfViewer = event.getSource();
336 String scale = pdfViewer.getUIFormSelectBox(SCALE_PAGE).getValue();
337 pdfViewer.setScale(Float.parseFloat(scale));
338 event.getRequestContext().addUIComponentToUpdateByAjax(pdfViewer);
339 }
340 }
341
342 static public class DownloadFileActionListener extends EventListener<PDFViewer> {
343 public void execute(Event<PDFViewer> event) throws Exception {
344 PDFViewer pdfViewer = event.getSource();
345 UIComponent uiParent = pdfViewer.getParent();
346 Method methodGetNode = pdfViewer.getMethod(uiParent, "getNode");
347 Node node = (Node)methodGetNode.invoke(uiParent, (Object[]) null);
348 node = getFileLangNode(node);
349 String repository = (String) pdfViewer.getMethod(uiParent, "getRepository").invoke(uiParent, (Object[]) null);
350 PDFViewerService pdfViewerService = pdfViewer.getApplicationComponent(PDFViewerService.class);
351 File file = pdfViewerService.getPDFDocumentFile(node, repository);
352 String fileName = node.getName();
353 int index = fileName.lastIndexOf('.');
354 if (index < 0) {
355 fileName += ".pdf";
356 } else if (index == fileName.length() - 1) {
357 fileName += "pdf";
358 } else {
359 String extension = fileName.substring(index + 1);
360 fileName = fileName.replace(extension, "pdf");
361 }
362 DownloadService dservice = pdfViewer.getApplicationComponent(DownloadService.class) ;
363 InputStreamDownloadResource dresource = new InputStreamDownloadResource(
364 new BufferedInputStream(new FileInputStream(file)), DMSMimeTypeResolver.getInstance().getMimeType(".pdf"));
365 dresource.setDownloadName(fileName) ;
366 String downloadLink = dservice.getDownloadLink(dservice.addDownloadResource(dresource)) ;
367
368 RequireJS requireJS = event.getRequestContext().getJavascriptManager().getRequireJS();
369 requireJS.require("SHARED/ecm-utils", "ecmutil").addScripts("ecmutil.ECMUtils.ajaxRedirect('" + downloadLink + "');");
370 event.getRequestContext().addUIComponentToUpdateByAjax(pdfViewer);
371 }
372 }
373
374 static public class ZoomInPageActionListener extends EventListener<PDFViewer> {
375 public void execute(Event<PDFViewer> event) throws Exception {
376 PDFViewer pdfViewer = event.getSource();
377 String[] arrValue = {"0.05f", "0.1f", "0.25f", "0.5f", "0.75f", "1.0f",
378 "1.25f", "1.5f", "2.0f", "3.0f"};
379 String scale = pdfViewer.getUIFormSelectBox(SCALE_PAGE).getValue();
380 if(scale.equals(arrValue[arrValue.length - 1])) return;
381 for(int i = 0; i < arrValue.length - 1; i++) {
382 if(scale.equals(arrValue[i])) {
383 pdfViewer.setScale(Float.parseFloat(arrValue[i + 1]));
384 pdfViewer.getUIFormSelectBox(SCALE_PAGE).setValue(arrValue[i + 1]);
385 break;
386 }
387 }
388 event.getRequestContext().addUIComponentToUpdateByAjax(pdfViewer);
389 }
390 }
391
392 static public class ZoomOutPageActionListener extends EventListener<PDFViewer> {
393 public void execute(Event<PDFViewer> event) throws Exception {
394 PDFViewer pdfViewer = event.getSource();
395 String scale = pdfViewer.getUIFormSelectBox(SCALE_PAGE).getValue();
396 String[] arrValue = {"0.05f", "0.1f", "0.25f", "0.5f", "0.75f", "1.0f",
397 "1.25f", "1.5f", "2.0f", "3.0f"};
398 if(scale.equals(arrValue[0])) return;
399 for(int i = 0; i < arrValue.length - 1; i++) {
400 if(scale.equals(arrValue[i])) {
401 pdfViewer.setScale(Float.parseFloat(arrValue[i - 1]));
402 pdfViewer.getUIFormSelectBox(SCALE_PAGE).setValue(arrValue[i - 1]);
403 break;
404 }
405 }
406 event.getRequestContext().addUIComponentToUpdateByAjax(pdfViewer);
407 }
408 }
409 static public Node getFileLangNode(Node currentNode) throws Exception {
410 if(currentNode.isNodeType("nt:unstructured")) {
411 if(currentNode.getNodes().getSize() > 0) {
412 NodeIterator nodeIter = currentNode.getNodes() ;
413 while(nodeIter.hasNext()) {
414 Node ntFile = nodeIter.nextNode() ;
415 if(ntFile.isNodeType("nt:file")) {
416 return ntFile ;
417 }
418 }
419 return currentNode ;
420 }
421 }
422 return currentNode ;
423 }
424
425 public String getActionOpenDocInDesktop() {
426 UIComponent uiParent = getParent();
427 String ret = "";
428 try {
429 Method method = getMethod(uiParent, "getActionOpenDocInDesktop");
430 if(method != null) ret = (String) method.invoke(uiParent, (Object[]) null);
431 } catch (NoSuchMethodException| IllegalArgumentException| IllegalAccessException| InvocationTargetException e) {
432 ret = "";
433 }
434 return ret;
435 }
436 }