View Javadoc
1   /*
2    * Copyright (C) 2003-2010 eXo Platform SAS.
3    *
4    * This program is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Affero General Public License
6    * as published by the Free Software Foundation; either version 3
7    * of the License, or (at your option) any later version.
8    *
9    * This program is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU General Public License for more details.
13   *
14   * You should have received a copy of the GNU General Public License
15   * along with this program; if not, see<http://www.gnu.org/licenses/>.
16   */
17  package org.exoplatform.social.plugin.doc;
18  
19  import java.io.InputStream;
20  
21  import javax.jcr.Node;
22  import javax.jcr.PathNotFoundException;
23  import javax.jcr.RepositoryException;
24  import javax.jcr.ValueFormatException;
25  import javax.portlet.PortletRequest;
26  
27  import org.apache.commons.io.FileUtils;
28  import org.apache.commons.lang.StringUtils;
29  
30  import org.exoplatform.commons.utils.CommonsUtils;
31  import org.exoplatform.container.PortalContainer;
32  import org.exoplatform.ecm.jcr.model.VersionNode;
33  import org.exoplatform.ecm.webui.utils.Utils;
34  import org.exoplatform.services.cms.documents.DocumentService;
35  import org.exoplatform.services.log.ExoLogger;
36  import org.exoplatform.services.log.Log;
37  import org.exoplatform.services.security.ConversationState;
38  import org.exoplatform.services.wcm.core.NodeLocation;
39  import org.exoplatform.services.wcm.core.NodetypeConstant;
40  import org.exoplatform.services.wcm.core.WebSchemaConfigService;
41  import org.exoplatform.services.wcm.friendly.FriendlyService;
42  import org.exoplatform.services.wcm.utils.WCMCoreUtils;
43  import org.exoplatform.services.wcm.webcontent.WebContentSchemaHandler;
44  import org.exoplatform.social.webui.activity.BaseUIActivity;
45  import org.exoplatform.social.webui.activity.UIActivitiesContainer;
46  import org.exoplatform.social.webui.composer.PopupContainer;
47  import org.exoplatform.web.application.ApplicationMessage;
48  import org.exoplatform.webui.application.WebuiRequestContext;
49  import org.exoplatform.webui.application.portlet.PortletRequestContext;
50  import org.exoplatform.webui.config.annotation.ComponentConfig;
51  import org.exoplatform.webui.config.annotation.EventConfig;
52  import org.exoplatform.webui.core.UIApplication;
53  import org.exoplatform.webui.core.lifecycle.UIFormLifecycle;
54  import org.exoplatform.webui.cssfile.CssClassManager;
55  import org.exoplatform.webui.cssfile.CssClassUtils;
56  import org.exoplatform.webui.event.Event;
57  import org.exoplatform.webui.event.EventListener;
58  
59  /**
60   * Created by The eXo Platform SAS
61   * Author : Zun
62   *          exo@exoplatform.com
63   * Jul 23, 2010  
64   */
65  
66  @ComponentConfig(
67     lifecycle = UIFormLifecycle.class,
68     template = "classpath:groovy/social/plugin/doc/UIDocActivity.gtmpl",
69     events = {
70       @EventConfig(listeners = UIDocActivity.DownloadDocumentActionListener.class),
71       @EventConfig(listeners = UIDocActivity.ViewDocumentActionListener.class),
72       @EventConfig(listeners = BaseUIActivity.LoadLikesActionListener.class),
73       @EventConfig(listeners = BaseUIActivity.ToggleDisplayCommentFormActionListener.class),
74       @EventConfig(listeners = BaseUIActivity.LikeActivityActionListener.class),
75       @EventConfig(listeners = BaseUIActivity.SetCommentListStatusActionListener.class),
76       @EventConfig(listeners = BaseUIActivity.PostCommentActionListener.class),
77       @EventConfig(listeners = BaseUIActivity.DeleteActivityActionListener.class),
78       @EventConfig(listeners = BaseUIActivity.DeleteCommentActionListener.class),
79       @EventConfig(listeners = BaseUIActivity.LikeCommentActionListener.class)
80     }
81   )
82  public class UIDocActivity extends BaseUIActivity {
83    
84    private static final Log LOG = ExoLogger.getLogger(UIDocActivity.class);
85    private static final String IMAGE_PREFIX = "image/";
86    private static final String DOCUMENT_POSTFIX = "/pdf";
87    
88    public static final String DOCLINK = "DOCLINK";
89    public static final String MESSAGE = "MESSAGE";
90    public static final String REPOSITORY = "REPOSITORY";
91    public static final String WORKSPACE = "WORKSPACE";
92    public static final String DOCNAME = "DOCNAME";
93    public static final String ID = "id";
94    public static final String DOCPATH = "DOCPATH";
95    
96    public static final String CONTENT_NAME       = "contentName";
97    public static final String CONTENT_LINK       = "contenLink";
98    public static final String IMAGE_PATH         = "imagePath";
99    public static final String MIME_TYPE          = "mimeType";
100   public static final String STATE              = "state";
101   public static final String AUTHOR             = "author";
102   public static final String DATE_CREATED       = "dateCreated";
103   public static final String LAST_MODIFIED      = "lastModified";
104   public static final String DOCUMENT_TYPE_LABEL= "docTypeLabel";  
105   public static final String DOCUMENT_TITLE     = "docTitle";  
106   public static final String DOCUMENT_VERSION   = "docVersion";  
107   public static final String DOCUMENT_SUMMARY   = "docSummary";
108   public static final String IS_SYMLINK         = "isSymlink";
109   
110   public String docLink;
111   public String message;
112   public String docName;
113   public String docPath;
114   public String repository;
115   public String workspace;
116 
117   private DocumentService documentService;
118 
119   public UIDocActivity() {
120     documentService = CommonsUtils.getService(DocumentService.class);
121   }
122 
123   protected boolean isPreviewable() {
124     return getMimeType().endsWith(DOCUMENT_POSTFIX);    
125   }
126   
127   protected boolean isImageFile() {
128     return getMimeType().startsWith(IMAGE_PREFIX);
129   }
130   
131   protected String getDocThumbnail(){    
132     String portalContainerName = PortalContainer.getCurrentPortalContainerName();
133     String restContextName = PortalContainer.getRestContextName(portalContainerName);
134     return new StringBuffer().append("/").append(portalContainerName).
135                                append("/").append(restContextName).
136                                append("/thumbnailImage/big").
137                                append("/").append(UIDocActivityComposer.REPOSITORY).
138                                append("/").append(UIDocActivityComposer.WORKSPACE).
139                                append(docPath).toString();
140   }
141   
142   protected String getSize() {
143     double size = 0;
144     Node docNode = getDocNode();
145     try {
146       if (docNode.hasNode(Utils.JCR_CONTENT)) {
147         Node contentNode = docNode.getNode(Utils.JCR_CONTENT);
148         if (contentNode.hasProperty(Utils.JCR_DATA)) {
149           size = contentNode.getProperty(Utils.JCR_DATA).getLength();
150         }
151         
152         return FileUtils.byteCountToDisplaySize((long)size);
153       }
154     } catch (PathNotFoundException e) {
155       return StringUtils.EMPTY;
156     } catch (ValueFormatException e) {
157       return StringUtils.EMPTY;
158     } catch (RepositoryException e) {
159       return StringUtils.EMPTY;
160     }
161     return StringUtils.EMPTY;
162   }
163   
164   protected int getVersion() {
165     try {
166       VersionNode rootVersion_ = new VersionNode(NodeLocation.getNodeByLocation(new NodeLocation(repository, workspace, docPath))
167                                                  .getVersionHistory().getRootVersion(), getDocNode().getSession());
168       if (rootVersion_ != null) {
169         return rootVersion_.getChildren().size();
170       }
171     } catch (Exception e) {
172         if(LOG.isDebugEnabled()) {
173           LOG.debug("cannot version node", e);
174         }
175     }
176     return 0;
177   }
178 
179   protected String getCssClassIconFile(String fileName, String fileType) {
180     String cssClass = CssClassUtils.getCSSClassByFileNameAndFileType(fileName, fileType, CssClassManager.ICON_SIZE.ICON_64).replace("uiIcon", "uiBgd");
181     return cssClass;
182   }
183 
184   protected boolean isDisplayThumbnail(String mimeType) {
185     if( mimeType.startsWith("application/pdf") || 
186         mimeType.startsWith("application/msword") || 
187         mimeType.startsWith("application/vnd.oasis.opendocument.text") || 
188         mimeType.startsWith("application/vnd.openxmlformats-officedocument.wordprocessingml.document") || 
189         mimeType.startsWith("application/rtf") ){
190       return true;
191     }
192     return false;
193   }
194 
195   public String getDocOpenUri() {
196     String uri = "";
197 
198     if(docPath != null) {
199       try {
200         uri = documentService.getLinkInDocumentsApp(docPath);
201       } catch(Exception e) {
202         LOG.error("Cannot get document open URI of node " + docPath + " : " + e.getMessage(), e);
203         uri = "";
204       }
205     }
206 
207     return uri;
208   }
209 
210   private boolean hasPermissionViewFile() {
211     return (getDocNode() != null);
212   }
213   
214   public static class ViewDocumentActionListener extends EventListener<UIDocActivity> {
215     @Override
216     public void execute(Event<UIDocActivity> event) throws Exception {
217       final UIDocActivity docActivity = event.getSource();
218       if (! docActivity.hasPermissionViewFile()) {
219         WebuiRequestContext ctx = event.getRequestContext();
220         UIApplication uiApplication = ctx.getUIApplication();
221         uiApplication.addMessage(new ApplicationMessage("UIDocActivity.msg.noPermission", null, ApplicationMessage.WARNING));
222         return;
223       }
224       final UIActivitiesContainer activitiesContainer = docActivity.getAncestorOfType(UIActivitiesContainer.class);
225       final PopupContainer popupContainer = activitiesContainer.getPopupContainer();
226 
227       if (docActivity.getChild(UIDocViewer.class) != null) {
228         docActivity.removeChild(UIDocViewer.class);
229       }
230       
231       UIDocViewer docViewer = popupContainer.createUIComponent(UIDocViewer.class, null, "DocViewer");
232       docViewer.docPath = docActivity.docPath;
233       docViewer.repository = docActivity.repository;
234       docViewer.workspace = docActivity.workspace;
235 
236       popupContainer.activate(docViewer, 800, 600, true);
237       event.getRequestContext().addUIComponentToUpdateByAjax(popupContainer);
238     }
239   }
240   
241   public static class DownloadDocumentActionListener extends EventListener<UIDocActivity> {
242     @Override
243     public void execute(Event<UIDocActivity> event) throws Exception {
244       UIDocActivity uiComp = event.getSource() ;
245       if (! uiComp.hasPermissionViewFile()) {
246         WebuiRequestContext ctx = event.getRequestContext();
247         UIApplication uiApplication = ctx.getUIApplication();
248         uiApplication.addMessage(new ApplicationMessage("UIDocActivity.msg.noPermission", null, ApplicationMessage.WARNING));
249         return;
250       }
251       String downloadLink = null;
252       if (getRealNode(uiComp.getDocNode()).getPrimaryNodeType().getName().equals(Utils.NT_FILE)) {
253         downloadLink = Utils.getDownloadRestServiceLink(uiComp.getDocNode());
254       }
255       event.getRequestContext().getJavascriptManager().addJavascript("ajaxRedirect('" + downloadLink + "');");
256     }
257     
258     private Node getRealNode(Node node) throws Exception {
259       // TODO: Need to add to check symlink node
260       if (node.isNodeType("nt:frozenNode")) {
261         String uuid = node.getProperty("jcr:frozenUuid").getString();
262         return node.getSession().getNodeByUUID(uuid);
263       }
264       return node;
265     }
266   }
267   
268   protected Node getDocNode() {
269     NodeLocation nodeLocation = new NodeLocation(repository, workspace, docPath);
270     return NodeLocation.getNodeByLocation(nodeLocation);
271   }
272   
273   /**
274    * Gets the webdav url.
275    * 
276    * @return the webdav url
277    * @throws Exception the exception
278    */
279   public String getWebdavURL() throws Exception {
280     Node contentNode = getDocNode();
281     NodeLocation nodeLocation = new NodeLocation(repository, workspace, docPath);
282     PortletRequestContext portletRequestContext = WebuiRequestContext.getCurrentInstance();
283     PortletRequest portletRequest = portletRequestContext.getRequest();
284     String repository = nodeLocation.getRepository();
285     String workspace = nodeLocation.getWorkspace();
286     String baseURI = portletRequest.getScheme() + "://" + portletRequest.getServerName() + ":"
287         + String.format("%s", portletRequest.getServerPort());
288 
289     FriendlyService friendlyService = WCMCoreUtils.getService(FriendlyService.class);
290     String link = "#";
291 
292     String portalName = PortalContainer.getCurrentPortalContainerName();
293     String restContextName = PortalContainer.getCurrentRestContextName();
294     if (contentNode.isNodeType("nt:frozenNode")) {
295       String uuid = contentNode.getProperty("jcr:frozenUuid").getString();
296       Node originalNode = contentNode.getSession().getNodeByUUID(uuid);
297       link = baseURI + "/" + portalName + "/" + restContextName + "/jcr/" + repository + "/"
298           + workspace + originalNode.getPath() + "?version=" + contentNode.getParent().getName();
299     } else {
300       link = baseURI + "/" + portalName + "/" + restContextName + "/jcr/" + repository + "/"
301           + workspace + contentNode.getPath();
302     }
303 
304     return friendlyService.getFriendlyUri(link);
305   }
306   
307   /**
308    * Gets the summary.
309    * 
310    * @return the summary of Node. Return empty string if catch an exception.
311    */
312   public String getSummary() {
313     String desc = "";
314     Node node = getDocNode();
315     try {
316       if (node != null) {
317         if (node.hasProperty("exo:summary")) {
318           desc = node.getProperty("exo:summary").getValue().getString();
319         } else if (node.hasNode("jcr:content")) {
320           Node content = node.getNode("jcr:content");
321           if (content.hasProperty("dc:description") && content.getProperty("dc:description").getValues().length > 0) {
322             desc = content.getProperty("dc:description").getValues()[0].getString();
323           }
324         }
325       }
326     } catch (RepositoryException re) {
327       if (LOG.isWarnEnabled())
328         LOG.warn("RepositoryException: ", re);
329     }
330 
331     return desc;
332   }
333   
334   public String getTitle() throws Exception {
335     return Utils.getTitle(getDocNode());
336   }
337   
338   /**
339    * get activity owner
340    * 
341    * @return activity owner
342    */
343   public static String getActivityOwnerId(Node node) {
344     String activityOwnerId = "";
345     ConversationState conversationState = ConversationState.getCurrent();
346     if (conversationState != null) {
347       activityOwnerId = conversationState.getIdentity().getUserId();
348     }else{
349       try {
350         activityOwnerId = node.getProperty("publication:lastUser").getString();
351       } catch (Exception e) {
352         LOG.info("No lastUser publication");
353       } 
354     }
355     return activityOwnerId;
356   }
357   
358   /**
359    * Gets the illustrative image.
360    * 
361    * @param node the node
362    * @return the illustrative image
363    */
364   public static String getIllustrativeImage(Node node) {
365     WebSchemaConfigService schemaConfigService = WCMCoreUtils.getService(WebSchemaConfigService.class);
366     WebContentSchemaHandler contentSchemaHandler = schemaConfigService.getWebSchemaHandlerByType(WebContentSchemaHandler.class);
367     Node illustrativeImage = null;
368     String uri = "";
369     try {
370       illustrativeImage = contentSchemaHandler.getIllustrationImage(node);
371       uri = generateThumbnailImageURI(illustrativeImage);
372     } catch (PathNotFoundException ex) {
373       return uri;
374     } catch (Exception e) { // WebContentSchemaHandler
375       LOG.warn(e.getMessage(), e);
376     }
377     return uri;
378   }
379   
380   /**
381    * Generate the Thumbnail Image URI.
382    * 
383    * @param file the node
384    * @return the Thumbnail uri with medium size
385    * @throws Exception the exception
386    */
387   public static String generateThumbnailImageURI(Node file) throws Exception {
388     StringBuilder builder = new StringBuilder();
389     NodeLocation fielLocation = NodeLocation.getNodeLocationByNode(file);
390     String repository = fielLocation.getRepository();
391     String workspaceName = fielLocation.getWorkspace();
392     String nodeIdentifiler = file.getPath().replaceFirst("/", "");
393     String portalName = PortalContainer.getCurrentPortalContainerName();
394     String restContextName = PortalContainer.getCurrentRestContextName();
395     InputStream stream = file.getNode(NodetypeConstant.JCR_CONTENT)
396                              .getProperty(NodetypeConstant.JCR_DATA)
397                              .getStream();
398     if (stream.available() == 0)
399       return null;
400     stream.close();
401     builder.append("/")
402            .append(portalName)
403            .append("/")
404            .append(restContextName)
405            .append("/")
406            .append("thumbnailImage/medium/")
407            .append(repository)
408            .append("/")
409            .append(workspaceName)
410            .append("/")
411            .append(nodeIdentifiler);
412     return builder.toString();
413   }
414   
415   /**
416    * Generate the viewer link to site explorer by node
417    * 
418    * @param node the node
419    * @return String the viewer link
420    * @throws RepositoryException
421    */
422   public static String getContentLink(Node node) throws Exception {
423     DocumentService documentService = CommonsUtils.getService(DocumentService.class);
424     return documentService.getLinkInDocumentsApp(node.getPath());
425   }
426   
427   /**
428    * Get the MimeType
429    * 
430    * @param node the node
431    * @return the MimeType
432    */
433   public static String getMimeType(Node node) {
434     try {
435       if (node.getPrimaryNodeType().getName().equals(NodetypeConstant.NT_FILE)) {
436         if (node.hasNode(NodetypeConstant.JCR_CONTENT))
437           return node.getNode(NodetypeConstant.JCR_CONTENT)
438                      .getProperty(NodetypeConstant.JCR_MIME_TYPE)
439                      .getString();
440       }
441     } catch (RepositoryException e) {
442       LOG.error(e.getMessage(), e);
443     }
444     return "";
445   }
446 
447   
448   private String getMimeType() {
449     String mimeType = "";    
450       try {
451         mimeType = getDocNode().getNode("jcr:content").getProperty("jcr:mimeType").getString();
452       } catch (ValueFormatException e) {
453         if (LOG.isDebugEnabled())
454           LOG.debug(e);
455         return StringUtils.EMPTY;
456       } catch (PathNotFoundException e) {
457         if (LOG.isDebugEnabled())
458           LOG.debug(e);
459         return StringUtils.EMPTY;
460       } catch (RepositoryException e) {
461         if (LOG.isDebugEnabled())
462           LOG.debug(e);
463         return StringUtils.EMPTY;
464       }
465     return mimeType;
466   }
467 }