View Javadoc
1   /*
2    * Copyright (C) 2003-2008 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.wcm.webui;
18  
19  import java.io.InputStream;
20  import java.security.AccessControlException;
21  import java.util.HashMap;
22  import java.util.HashSet;
23  import java.util.List;
24  import java.util.regex.Matcher;
25  import java.util.regex.Pattern;
26  
27  import javax.jcr.Node;
28  import javax.jcr.NodeIterator;
29  import javax.jcr.RepositoryException;
30  import javax.jcr.Session;
31  import javax.jcr.Value;
32  import javax.jcr.Workspace;
33  import javax.jcr.nodetype.NodeType;
34  import javax.jcr.query.Query;
35  import javax.jcr.query.QueryManager;
36  import javax.portlet.PortletMode;
37  import javax.portlet.PortletPreferences;
38  
39  import org.exoplatform.container.PortalContainer;
40  import org.exoplatform.container.configuration.ConfigurationManager;
41  import org.exoplatform.download.DownloadService;
42  import org.exoplatform.download.InputStreamDownloadResource;
43  
44  import org.exoplatform.ecm.utils.text.Text;
45  import org.exoplatform.ecm.utils.lock.LockUtil;
46  import org.exoplatform.portal.application.PortalRequestContext;
47  import org.exoplatform.portal.config.UserACL;
48  import org.exoplatform.portal.config.UserPortalConfigService;
49  import org.exoplatform.portal.config.model.PortalConfig;
50  import org.exoplatform.portal.mop.SiteType;
51  import org.exoplatform.portal.mop.page.PageContext;
52  import org.exoplatform.portal.mop.page.PageKey;
53  import org.exoplatform.portal.mop.SiteKey;
54  import org.exoplatform.portal.mop.user.UserNavigation;
55  import org.exoplatform.portal.mop.user.UserNode;
56  import org.exoplatform.portal.mop.user.UserPortal;
57  import org.exoplatform.portal.webui.page.UIPage;
58  import org.exoplatform.portal.webui.page.UIPageBody;
59  import org.exoplatform.portal.webui.portal.UIPortal;
60  import org.exoplatform.portal.webui.util.Util;
61  import org.exoplatform.portal.webui.workspace.UIMaskWorkspace;
62  import org.exoplatform.portal.webui.workspace.UIPortalApplication;
63  import org.exoplatform.portal.webui.workspace.UIWorkingWorkspace;
64  import org.exoplatform.services.cms.drives.DriveData;
65  import org.exoplatform.services.cms.drives.ManageDriveService;
66  import org.exoplatform.services.cms.link.LinkManager;
67  import org.exoplatform.services.cms.mimetype.DMSMimeTypeResolver;
68  import org.exoplatform.services.jcr.RepositoryService;
69  import org.exoplatform.services.jcr.access.PermissionType;
70  import org.exoplatform.services.jcr.core.ExtendedNode;
71  import org.exoplatform.services.log.ExoLogger;
72  import org.exoplatform.services.log.Log;
73  import org.exoplatform.services.security.Identity;
74  import org.exoplatform.services.security.IdentityRegistry;
75  import org.exoplatform.services.security.MembershipEntry;
76  import org.exoplatform.services.wcm.core.NodeLocation;
77  import org.exoplatform.services.wcm.core.WCMConfigurationService;
78  import org.exoplatform.services.wcm.navigation.NavigationUtils;
79  import org.exoplatform.services.wcm.publication.PublicationDefaultStates;
80  import org.exoplatform.services.wcm.publication.WCMComposer;
81  import org.exoplatform.services.wcm.publication.WCMPublicationService;
82  import org.exoplatform.services.wcm.utils.WCMCoreUtils;
83  import org.exoplatform.wcm.webui.core.UIPopupWindow;
84  import org.exoplatform.web.application.ApplicationMessage;
85  import org.exoplatform.web.application.RequestContext;
86  import org.exoplatform.web.url.navigation.NavigationResource;
87  import org.exoplatform.web.url.navigation.NodeURL;
88  import org.exoplatform.webui.application.WebuiRequestContext;
89  import org.exoplatform.webui.application.portlet.PortletRequestContext;
90  import org.exoplatform.webui.core.UIApplication;
91  import org.exoplatform.webui.core.UIComponent;
92  import org.exoplatform.webui.core.UIContainer;
93  import org.exoplatform.webui.core.UIPopupContainer;
94  import org.exoplatform.webui.core.UIPortletApplication;
95  import com.ibm.icu.text.Transliterator;
96  
97  /**
98   * Created by The eXo Platform SAS Author : Hoa Pham hoa.phamvu@exoplatform.com
99   * Oct 23, 2008
100  */
101 public class Utils {
102 
103   /** The Quick edit attribute for HTTPSession */
104   public static final String TURN_ON_QUICK_EDIT = "turnOnQuickEdit";
105 
106   private static final Log LOG = ExoLogger.getExoLogger(Utils.class);
107 
108   private static final String SQL_PARAM_PATTERN = "\\$\\{([^\\$\\{\\}])+\\}";
109   
110   private static final String JCR_CONTENT = "jcr:content";
111 
112   private static final String JCR_DATA = "jcr:data";
113 
114   private static final String JCR_MIMETYPE = "jcr:mimeType";  
115 
116   private static final String NT_FILE = "nt:file";
117 
118   private static final String NT_UNSTRUCTURED = "nt:unstructured";
119   
120   private static final String DOCUMENTS_ACTIVITY = "documents";
121 
122   /**
123    * Checks if is edits the portlet in create page wizard.
124    * @return true, if is edits the portlet in create page wizard
125    */
126   public static boolean isEditPortletInCreatePageWizard() {
127     UIPortalApplication portalApplication = Util.getUIPortalApplication();
128     UIMaskWorkspace uiMaskWS = portalApplication.getChildById(UIPortalApplication.UI_MASK_WS_ID);
129     // show maskworkpace is being in Portal page edit mode
130     if (uiMaskWS.getWindowWidth() > 0 && uiMaskWS.getWindowHeight() < 0)
131       return true;
132     return false;
133   }
134 
135   /**
136    * Checks if is quick editmode.
137    *
138    * @param container the current container
139    * @param popupWindowId the popup window id
140    *
141    * @return true, if is quick editmode
142    */
143   public static boolean isQuickEditMode(UIContainer container, String popupWindowId) {
144     UIPopupContainer popupContainer = getPopupContainer(container);
145     if (popupContainer == null)
146       return false;
147     UIPopupWindow popupWindow = popupContainer.getChildById(popupWindowId);
148     if (popupWindow == null)
149       return false;
150     return true;
151   }
152 
153   /**
154    * Check if the portlet current mode is view mode or not
155    * @param pContext The request context of a portlet
156    *
157    * @return return true if current portlet mode is view mode; otherwise return false
158    */
159   public static boolean isPortletViewMode(PortletRequestContext pContext) {
160     return PortletMode.VIEW.equals(pContext.getApplicationMode());
161   }
162 
163   public static boolean isPortalEditMode() {
164     return Util.getUIPortalApplication().getModeState() != UIPortalApplication.NORMAL_MODE;
165   }
166 
167   public static String getRealPortletId(PortletRequestContext portletRequestContext) {
168     String portletId = portletRequestContext.getWindowId();
169     int modeState = Util.getUIPortalApplication().getModeState();
170     switch (modeState) {
171     case UIPortalApplication.NORMAL_MODE:
172       return portletId;
173     case UIPortalApplication.APP_BLOCK_EDIT_MODE:
174       return "UIPortlet-" + portletId;
175     case UIPortalApplication.APP_VIEW_EDIT_MODE:
176       return "EditMode-" + portletId;
177     default:
178       return null;
179     }
180   }
181 
182   /**
183    * Can edit current portal.
184    *
185    * @param remoteUser the remote user
186    * @return true, if successful
187    * @throws Exception the exception
188    */
189   public static boolean canEditCurrentPortal(String remoteUser) throws Exception {
190     if (remoteUser == null)
191       return false;
192     IdentityRegistry identityRegistry = Util.getUIPortalApplication()
193                                             .getApplicationComponent(IdentityRegistry.class);
194     Identity identity = identityRegistry.getIdentity(remoteUser);
195     if (identity == null)
196       return false;
197     UIPortal uiPortal = Util.getUIPortal();
198     // this code only work for single edit permission
199     String editPermission = uiPortal.getEditPermission();
200     MembershipEntry membershipEntry = MembershipEntry.parse(editPermission);
201     return identity.isMemberOf(membershipEntry);
202   }
203 
204   /**
205    * Clean string.
206    *
207    * @param str the str
208    * @return the string
209    */
210   public static String cleanString(String str) {
211     Transliterator accentsconverter = Transliterator.getInstance("Latin; NFD; [:Nonspacing Mark:] Remove; NFC;");
212     str = accentsconverter.transliterate(str);
213     // the character ? seems to not be changed to d by the transliterate
214     // function
215     StringBuffer cleanedStr = new StringBuffer(str.trim());
216     // delete special character
217     for (int i = 0; i < cleanedStr.length(); i++) {
218       char c = cleanedStr.charAt(i);
219       if (c == ' ') {
220         if (i > 0 && cleanedStr.charAt(i - 1) == '-') {
221           cleanedStr.deleteCharAt(i--);
222         } else {
223           c = '-';
224           cleanedStr.setCharAt(i, c);
225         }
226         continue;
227       }
228       if (i > 0 && !(Character.isLetterOrDigit(c) || c == '-')) {
229         cleanedStr.deleteCharAt(i--);
230         continue;
231       }
232       if (i > 0 && c == '-' && cleanedStr.charAt(i - 1) == '-')
233         cleanedStr.deleteCharAt(i--);
234     }
235     return cleanedStr.toString().toLowerCase();
236   }
237 
238   /**
239    * Refresh whole portal by AJAX.
240    *
241    * @param context the portlet request context
242    */
243   public static void updatePortal(PortletRequestContext context) {
244     UIPortalApplication portalApplication = Util.getUIPortalApplication();
245     PortalRequestContext portalRequestContext = (PortalRequestContext) context.getParentAppRequestContext();
246     UIWorkingWorkspace uiWorkingWS = portalApplication.getChildById(UIPortalApplication.UI_WORKING_WS_ID);
247     portalRequestContext.addUIComponentToUpdateByAjax(uiWorkingWS);
248     portalRequestContext.ignoreAJAXUpdateOnPortlets(true);
249   }
250 
251   /**
252    * Gets the viewable node by WCMComposer (depends on site mode)
253    *
254    * @param repository the repository's name
255    * @param workspace the workspace's name
256    * @param nodeIdentifier the node's path or node's UUID
257    * @return the viewable node. Return <code>null</code> if
258    *         <code>nodeIdentifier</code> is invalid
259    * @see #getViewableNodeByComposer(String repository, String workspace, String
260    *      nodeIdentifier, String version) getViewableNodeByComposer()
261    */
262   public static Node getViewableNodeByComposer(String repository,
263                                                String workspace,
264                                                String nodeIdentifier) {
265     return getViewableNodeByComposer(repository, workspace, nodeIdentifier, null);
266   }
267 
268   /**
269    * Gets the viewable node by WCMComposer (depends on site mode)
270    *
271    * @param repository the repository's name
272    * @param workspace the workspace's name
273    * @param nodeIdentifier the node's path or node's UUID
274    * @param version the base version (e.g. <code>WCMComposer.BASE_VERSION</code>
275    *          )
276    * @return the viewable node. Return <code>null</code> if
277    *         <code>nodeIdentifier</code> is invalid
278    * @see #getViewableNodeByComposer(String repository, String workspace, String
279    *      nodeIdentifier) getViewableNodeByComposer()
280    * @see WCMComposer
281    */
282   public static Node getViewableNodeByComposer(String repository,
283                                                String workspace,
284                                                String nodeIdentifier,
285                                                String version) {
286     return getViewableNodeByComposer(repository, workspace, nodeIdentifier, version, WCMComposer.VISIBILITY_USER);
287   }
288 
289   /**
290    * Gets the viewable node by WCMComposer (depends on site mode)
291    *
292    * @param repository the repository's name
293    * @param workspace the workspace's name
294    * @param nodeIdentifier the node's path or node's UUID
295    * @param version the base version (e.g. <code>WCMComposer.BASE_VERSION</code>
296    *          )
297    * @param cacheVisibility the visibility of cache
298    *
299    * @return the viewable node. Return <code>null</code> if
300    *         <code>nodeIdentifier</code> is invalid
301    * @see #getViewableNodeByComposer(String repository, String workspace, String
302    *      nodeIdentifier) getViewableNodeByComposer()
303    * @see WCMComposer
304    */
305   public static Node getViewableNodeByComposer(String repository,
306                                                String workspace,
307                                                String nodeIdentifier,
308                                                String version,
309                                                String cacheVisibility) {
310     try {
311       HashMap<String, String> filters = new HashMap<String, String>();
312       StringBuffer filterLang = new StringBuffer(Util.getPortalRequestContext()
313                                                      .getLocale()
314                                                      .getLanguage());
315       String country = Util.getPortalRequestContext().getLocale().getCountry();
316       if (country != null && country.length() > 0) {
317         filterLang.append("_").append(country);
318       }
319       filters.put(WCMComposer.FILTER_LANGUAGE, filterLang.toString());
320       filters.put(WCMComposer.FILTER_MODE, Utils.getCurrentMode());
321       PortletRequestContext portletRequestContext = WebuiRequestContext.getCurrentInstance();
322       PortletMode portletMode = portletRequestContext.getApplicationMode();
323       filters.put(WCMComposer.PORTLET_MODE, portletMode.toString());
324       if (version != null)
325         filters.put(WCMComposer.FILTER_VERSION, version);
326       filters.put(WCMComposer.FILTER_VISIBILITY, cacheVisibility);
327       return WCMCoreUtils.getService(WCMComposer.class)
328                          .getContent(workspace,
329                                  Text.escapeIllegalJcrChars(nodeIdentifier),
330                                      filters,
331                                      WCMCoreUtils.getUserSessionProvider());
332     } catch (Exception e) {
333       return null;
334     }
335   }
336 
337   /**
338    * Gets the current mode of the site
339    *
340    * @return the current mode (e.g. <code>WCMComposer.MODE_EDIT</code>)
341    * @see WCMComposer
342    */
343   public static String getCurrentMode() {
344     Object isQuickEditable = Util.getPortalRequestContext()
345                                  .getRequest()
346                                  .getSession()
347                                  .getAttribute(TURN_ON_QUICK_EDIT);
348     if (isQuickEditable == null)
349       return WCMComposer.MODE_LIVE;
350     boolean turnOnQuickEdit = Boolean.parseBoolean(isQuickEditable.toString());
351     return turnOnQuickEdit ? WCMComposer.MODE_EDIT : WCMComposer.MODE_LIVE;
352   }
353 
354   /**
355    * Check if the current mode is live mode or not
356    *
357    * @return return true if current mode is WCMComposer.MODE_LIVE; otherwise
358    *         false.
359    */
360   public static boolean isLiveMode() {
361     return WCMComposer.MODE_LIVE.equals(getCurrentMode());
362   }
363 
364   /**
365    * Check if the content is draft and current mode of the site is edit mode
366    *
367    * @param content the content node.
368    * @return true, the content is draft and current mode is edit mode, otherwise
369    *         return false.
370    */
371   public static boolean isShowDraft(Node content) {
372     if (content == null)
373       return false;
374     try {
375       if (content.isNodeType("nt:frozenNode"))
376         return false;
377       WCMPublicationService wcmPublicationService = WCMCoreUtils.getService(WCMPublicationService.class);
378       String contentState = wcmPublicationService.getContentState(content);
379       boolean isDraftContent = false;
380       if (PublicationDefaultStates.DRAFT.equals(contentState))
381         isDraftContent = true;
382       boolean isShowDraft = false;
383       if (WCMComposer.MODE_EDIT.equals(getCurrentMode()))
384         isShowDraft = true;
385       return isDraftContent && isShowDraft;
386     } catch (Exception e) {
387       return false;
388     }
389   }
390 
391   /**
392    * Check if the current mode of the site is edit mode
393    *
394    * @return true, if current mode is edit mode
395    */
396   public static boolean isShowQuickEdit() {
397     try {
398       boolean isEditMode = false;
399       if (WCMComposer.MODE_EDIT.equals(getCurrentMode()))
400         isEditMode = true;
401       return isEditMode;
402     } catch (Exception e) {
403       return false;
404     }
405   }
406 
407   /**
408    * Check if the user can delete the current node
409    *
410    * @return true, if current mode is edit mode
411    * @throws RepositoryException
412    * @throws AccessControlException
413    */
414   public static boolean isShowDelete(Node content) throws RepositoryException {
415     boolean isEditMode = false;
416     if (WCMComposer.MODE_EDIT.equals(getCurrentMode())) isEditMode = true;
417     try {
418       ((ExtendedNode) content).checkPermission(PermissionType.SET_PROPERTY);
419       ((ExtendedNode) content).checkPermission(PermissionType.ADD_NODE);
420       ((ExtendedNode) content).checkPermission(PermissionType.REMOVE);
421     } catch (AccessControlException e) {
422       isEditMode = false;
423     } catch (Exception e) {
424       String nodePath = null;
425       try {
426         nodePath = content.getPath();
427       } catch (Exception e1) {
428         // Nothing to log
429       }
430       LOG.error("Error while checking permissions on node " + nodePath, e);
431       isEditMode = false;
432     }
433     return isEditMode;
434   }
435 
436   /**
437    * Check if the content is editable and current mode of the site is edit mode
438    *
439    * @param content the content node
440    * @return true if there is no content if the content is editable and current
441    *         mode is edit mode
442    */
443   public static boolean isShowQuickEdit(Node content) {
444     if (content == null)
445       return true;
446     try {
447       boolean isEditMode = false;
448       if (WCMComposer.MODE_EDIT.equals(getCurrentMode())
449           || Util.getUIPortalApplication().getModeState() != UIPortalApplication.NORMAL_MODE)
450         isEditMode = true;
451       ((ExtendedNode) content).checkPermission(PermissionType.SET_PROPERTY);
452       ((ExtendedNode) content).checkPermission(PermissionType.ADD_NODE);
453       ((ExtendedNode) content).checkPermission(PermissionType.REMOVE);
454       return isEditMode;
455     } catch (Exception e) {
456       return false;
457     }
458   }
459 
460   public static String getEditLink(Node node, boolean isEditable, boolean isNew) {
461     try {
462       ManageDriveService manageDriveService = WCMCoreUtils.getService(ManageDriveService.class);
463       String nodeWorkspace = node.getSession().getWorkspace().getName();
464       String driveWorkspace = nodeWorkspace;
465       List<DriveData> listDrive = manageDriveService.getAllDrives();
466       for(DriveData drive : listDrive) {
467         if(drive.getWorkspace().equals(nodeWorkspace) && node.getPath().startsWith(drive.getHomePath())) {
468           driveWorkspace = drive.getName();
469           break;
470         }
471       }
472       String itemPath = driveWorkspace + node.getPath();
473       return getEditLink(itemPath, isEditable, isNew);
474     } catch (RepositoryException re) {
475       return null;
476     } catch(Exception e) {
477       return null;
478     }
479   }
480   
481   public static String getActivityEditLink(Node node) {
482     try {
483       String itemPath = node.getSession().getWorkspace().getName() + node.getPath();
484       return getActivityEditLink(itemPath);
485     } catch (RepositoryException e) {
486       return null;
487     }
488   }
489 
490   /**
491    * Creates a restfull compliant link to the editor for editing a content,
492    * adding a content or managing contents. Example : Add Content : isEditable =
493    * false, isNew = true, itemPath = the parent folder path Edit Content :
494    * isEditable = true, isNew = false, itemPath = the content path Manage
495    * Contents = isEditable = false, isNew = false, itemPath = the folder path
496    *
497    * @param itemPath
498    * @param isEditable
499    * @param isNew
500    * @return
501    */
502   public static String getEditLink(String itemPath, boolean isEditable, boolean isNew) {
503     PortalRequestContext pContext = Util.getPortalRequestContext();
504     String backto = pContext.getRequestURI();
505     WCMConfigurationService configurationService = Util.getUIPortalApplication()
506                                                        .getApplicationComponent(WCMConfigurationService.class);
507     String editorPageURI = configurationService.getRuntimeContextParam(
508                                isEditable || isNew ? WCMConfigurationService.EDITOR_PAGE_URI :
509                                                      WCMConfigurationService.SITE_EXPLORER_URI);
510     UserNode editorNode = getEditorNode(editorPageURI);
511 
512     if (editorNode == null) {
513       return "";
514     }
515 
516     NodeURL nodeURL = pContext.createURL(NodeURL.TYPE);
517     nodeURL.setNode(editorNode).setQueryParameterValue("path", itemPath);
518     if (isEditable) {
519       nodeURL.setQueryParameterValue("edit", "true");
520     }
521     if (isNew) {
522       nodeURL.setQueryParameterValue("addNew", "true");
523     }
524     nodeURL.setQueryParameterValue(org.exoplatform.ecm.webui.utils.Utils.URL_BACKTO, backto);
525 
526     return nodeURL.toString();
527   }
528   
529   public static String getActivityEditLink(String itemPath) {
530     PortalRequestContext pContext = Util.getPortalRequestContext();    
531     String siteType = pContext.getSiteKey().getType().getName();
532     String backto = pContext.getRequestURI();
533     WCMConfigurationService configurationService = Util.getUIPortalApplication()
534     		.getApplicationComponent(WCMConfigurationService.class);
535     
536     String editorPageURI = null;
537     if(siteType.equals(PortalConfig.PORTAL_TYPE))
538       editorPageURI = configurationService.getRuntimeContextParam(WCMConfigurationService.EDIT_PAGE_URI);
539     else if(siteType.equals(PortalConfig.GROUP_TYPE)) {
540       StringBuffer sb = new StringBuffer();      
541     	editorPageURI = pContext.getSiteName();
542     	editorPageURI = editorPageURI.substring(editorPageURI.lastIndexOf("/")+1, editorPageURI.length());
543     	sb.append(editorPageURI).append("/").append(DOCUMENTS_ACTIVITY);
544     	editorPageURI = sb.toString();
545     }
546     UserNode editorNode = getEditorNode(editorPageURI, siteType);
547 
548     if (editorNode == null) {
549       return "";
550     }
551 
552     NodeURL nodeURL = pContext.createURL(NodeURL.TYPE);
553     nodeURL.setNode(editorNode);
554     nodeURL.setQueryParameterValue("path", itemPath);
555     nodeURL.setQueryParameterValue("edit", "true");   
556     nodeURL.setQueryParameterValue(org.exoplatform.ecm.webui.utils.Utils.URL_BACKTO, backto);
557 
558     return nodeURL.toString();
559   }
560   
561   private static UserNode getEditorNode(String editorPageURI, String siteType) {
562     UserPortal userPortal = Util.getPortalRequestContext().getUserPortalConfig().getUserPortal();
563     List<UserNavigation> allNavs = userPortal.getNavigations();
564 
565     for (UserNavigation nav : allNavs) {
566       if (nav.getKey().getType().getName().equalsIgnoreCase(siteType)) {
567         UserNode userNode = userPortal.resolvePath(nav, null, editorPageURI);
568         if (userNode != null) {
569           return userNode;
570         }
571       }
572     }
573     return null;
574   }
575 
576   private static UserNode getEditorNode(String editorPageURI) {
577     UserPortal userPortal = Util.getPortalRequestContext().getUserPortalConfig().getUserPortal();
578     List<UserNavigation> allNavs = userPortal.getNavigations();
579 
580     for (UserNavigation nav : allNavs) {
581       if (nav.getKey().getType().equals(SiteType.GROUP)) {
582         UserNode userNode = userPortal.resolvePath(nav, null, editorPageURI);
583         if (userNode != null) {
584           return userNode;
585         }
586       }
587     }
588     return null;
589   }
590 
591   /**
592    * Creates the popup window. Each portlet have a <code>UIPopupContainer</code>
593    * . <br>
594    * Every <code>UIPopupWindow</code> created by this method is belong to this
595    * container.
596    *
597    * @param container the current container
598    * @param component the component which will be display as a popup
599    * @param popupWindowId the popup's ID
600    * @param width the width of the popup
601    * @throws Exception the exception
602    */
603   public static void createPopupWindow(UIContainer container,
604                                        UIComponent component,
605                                        String popupWindowId,
606                                        int width) throws Exception {
607     UIPopupContainer popupContainer = initPopup(container, component, popupWindowId, width);
608     WebuiRequestContext requestContext = WebuiRequestContext.getCurrentInstance();
609     requestContext.addUIComponentToUpdateByAjax(popupContainer);
610   }
611 
612   /**
613    * Creates the popup window. Each portlet have a <code>UIPopupContainer</code>
614    * . <br>
615    * Every <code>UIPopupWindow</code> created by this method is belong to this
616    * container.
617    *
618    * @param container the current container
619    * @param component the component which will be display as a popup
620    * @param popupWindowId the popup's ID
621    * @param width the width of the popup
622    * @param isShowMask Set as true to create mask layer
623    * @throws Exception the exception
624    */
625   public static void createPopupWindow(UIContainer container,
626                                        UIComponent component,
627                                        String popupWindowId,
628                                        int width, boolean isShowMask) throws Exception {
629     UIPopupContainer popupContainer = initPopup(container, component, popupWindowId, width);
630     UIPopupWindow popupWindow = popupContainer.getChildById(popupWindowId);
631     popupWindow.setShowMask(isShowMask);
632     WebuiRequestContext requestContext = WebuiRequestContext.getCurrentInstance();
633     requestContext.addUIComponentToUpdateByAjax(popupContainer);
634   }
635 
636   /**
637    * Creates the popup window. Each portlet have a <code>UIPopupContainer</code>
638    * . <br>
639    * Every <code>UIPopupWindow</code> created by this method is belong to this
640    * container.
641    *
642    * @param container the current container
643    * @param component the component which will be display as a popup
644    * @param popupWindowId the popup's ID
645    * @param width the width of the popup
646    * @param top the top of the popup
647    * @param left the left of the popup
648    * @throws Exception the exception
649    */
650   public static void createPopupWindow(UIContainer container,
651       UIComponent component,
652       String popupWindowId,
653       int width, int top, int left) throws Exception {
654     UIPopupContainer popupContainer = initPopup(container, component, popupWindowId, width);
655     UIPopupWindow popupWindow = popupContainer.getChildById(popupWindowId);
656     popupWindow.setCoordindate(top, left);
657     WebuiRequestContext requestContext = WebuiRequestContext.getCurrentInstance();
658     requestContext.addUIComponentToUpdateByAjax(popupContainer);
659   }
660   
661   public static void createPopupWindow(UIContainer container,
662                                        UIComponent component,
663                                        String popupWindowId,
664                                        boolean isMiddle,
665                                        int width) throws Exception {
666     UIPopupContainer popupContainer = initPopup(container, component, popupWindowId, width);
667     UIPopupWindow popupWindow = popupContainer.getChildById(popupWindowId);
668     popupWindow.setMiddle(isMiddle);
669     WebuiRequestContext requestContext = WebuiRequestContext.getCurrentInstance();
670     requestContext.addUIComponentToUpdateByAjax(popupContainer);
671   }
672 
673   private static UIPopupContainer initPopup(UIContainer container,
674       UIComponent component,
675       String popupWindowId,
676       int width) throws Exception {
677     UIPopupContainer popupContainer = getPopupContainer(container);
678     popupContainer.removeChildById(popupWindowId);
679     popupContainer.removeChildById("UIPopupWindow");
680     UIPopupWindow popupWindow = popupContainer.addChild(UIPopupWindow.class, null, popupWindowId);
681     popupWindow.setUIComponent(component);
682     popupWindow.setWindowSize(width, 0);
683     popupWindow.setShow(true);
684     popupWindow.setRendered(true);
685     popupWindow.setResizable(true);
686     popupWindow.setShowMask(true);
687     return popupContainer;
688   }
689 
690 
691   /**
692    * Close popup window.
693    *
694    * @param container the current container
695    * @param popupWindowId the popup's ID
696    */
697   public static void closePopupWindow(UIContainer container, String popupWindowId) {
698     UIPopupContainer popupContainer = getPopupContainer(container);
699     popupContainer.removeChildById(popupWindowId);
700   }
701 
702   /**
703    * Update popup window.
704    *
705    * @param container the container
706    * @param component the component which will be replace for the old one in the
707    *          same popup
708    * @param popupWindowId the popup's ID
709    */
710   public static void updatePopupWindow(UIContainer container,
711                                        UIComponent component,
712                                        String popupWindowId) {
713     UIPopupContainer popupContainer = getPopupContainer(container);
714     UIPopupWindow popupWindow = popupContainer.getChildById(popupWindowId);
715     popupWindow.setUIComponent(component);
716   }
717 
718   /**
719    * Gets the popup container.
720    *
721    * @param container the current container
722    * @return the popup container
723    */
724   public static UIPopupContainer getPopupContainer(UIContainer container) {
725     if (container instanceof UIPortletApplication)
726       return container.getChild(UIPopupContainer.class);
727     UIPortletApplication portletApplication = container.getAncestorOfType(UIPortletApplication.class);
728     return portletApplication.getChild(UIPopupContainer.class);
729   }
730 
731   /**
732    * Creates the popup message.
733    *
734    * @param container the current container
735    * @param message the message key
736    * @param args the arguments to show in the message
737    * @param type the message's type (e.g. <code>ApplicationMessage.INFO</code>)
738    * @see ApplicationMessage
739    */
740   public static void createPopupMessage(UIContainer container,
741                                         String message,
742                                         Object[] args,
743                                         int type) {
744     UIApplication application = container.getAncestorOfType(UIApplication.class);
745     application.addMessage(new ApplicationMessage(message, args, type));
746   }
747 
748   /**
749    * Get one portlet preference by name
750    *
751    * @param preferenceName the name of preference
752    * @return the portlet preference's value
753    */
754   public static String getPortletPreference(String preferenceName) {
755     PortletRequestContext portletRequestContext = WebuiRequestContext.getCurrentInstance();
756     PortletPreferences preferences = portletRequestContext.getRequest().getPreferences();
757     return preferences.getValue(preferenceName, null);
758   }
759 
760   /**
761    * Get all portlet preferences
762    *
763    * @return all portlet preferences
764    */
765   public static PortletPreferences getAllPortletPreferences() {
766     PortletRequestContext portletRequestContext = WebuiRequestContext.getCurrentInstance();
767     return portletRequestContext.getRequest().getPreferences();
768   }
769 
770   /**
771    * Check if the node is viewable for the current user or not viewable. <br>
772    * return True if the node is viewable, otherwise will return False
773    *
774    * @param node: The node to check
775    */
776   public static boolean isViewable(Node node) {
777     try {
778       node.refresh(true);
779       ((ExtendedNode) node).checkPermission(PermissionType.READ);
780     } catch (Exception e) {
781       return false;
782     }
783     return true;
784   }
785 
786   /**
787    * Get the real node from frozen node, symlink node return True if the node is
788    * viewable, otherwise will return False
789    *
790    * @param node: The node to check
791    */
792   public static Node getRealNode(Node node) throws Exception {
793     // TODO: Need to add to check symlink node
794     if (node.isNodeType("nt:frozenNode")) {
795       String uuid = node.getProperty("jcr:frozenUuid").getString();
796       return node.getSession().getNodeByUUID(uuid);
797     }
798     return node;
799   }
800 
801   public static String getRealNodePath(Node node) throws Exception {
802     if (node.isNodeType("nt:frozenNode")) {
803       Node realNode = getRealNode(node);
804       return Text.escape(realNode.getPath(),'%',true) + "?version=" + node.getParent().getName();
805     }
806     return Text.escape(node.getPath(),'%',true);
807   }
808 
809   public static String getWebdavURL(Node node) throws Exception {
810     return getWebdavURL(node, true);
811   }
812 
813   public static String getWebdavURL(Node node, boolean withTimeParam) throws Exception {
814     return getWebdavURL(node, withTimeParam, true);
815   }
816 
817   public static String getWebdavURL(Node node, boolean withTimeParam, boolean isGetRealNodePath) throws Exception {
818     NodeLocation location = NodeLocation.getNodeLocationByNode(getRealNode(node));
819     String repository = location.getRepository();
820     String workspace = location.getWorkspace();
821     String currentProtal = PortalContainer.getCurrentRestContextName();
822     String portalName = PortalContainer.getCurrentPortalContainerName();
823 
824     String originalNodePath = isGetRealNodePath ? getRealNodePath(node) : Text.escape(node.getPath(),'%',true);
825     StringBuffer imagePath = new StringBuffer();
826     imagePath.append("/")
827              .append(portalName)
828              .append("/")
829              .append(currentProtal)
830              .append("/jcr/")
831              .append(repository)
832              .append("/")
833              .append(workspace)
834              .append(originalNodePath);
835     if (withTimeParam) {
836       if (imagePath.indexOf("?") > 0) {
837         imagePath.append("&time=");
838       } else {
839         imagePath.append("?time=");
840       }
841       imagePath.append(System.currentTimeMillis());
842     }
843     return imagePath.toString();
844   }
845 
846   /**
847    * GetRealNode
848    *
849    * @param strRepository
850    * @param strWorkspace
851    * @param strIdentifier
852    * @return the required node/ the target of a symlink node / null if node was
853    *         in trash.
854    * @throws RepositoryException
855    */
856   public static Node getRealNode(String strRepository,
857                                  String strWorkspace,
858                                  String strIdentifier,
859                                  boolean isWCMBase) throws RepositoryException {
860     return getRealNode(strRepository, strWorkspace, strIdentifier, isWCMBase, WCMComposer.VISIBILITY_USER);
861   }
862 
863   /**
864    * GetRealNode
865    *
866    * @param strRepository
867    * @param strWorkspace
868    * @param strIdentifier
869    * @param cacheVisibility the visibility of cache
870    *
871    * @return the required node/ the target of a symlink node / null if node was
872    *         in trash.
873    * @throws RepositoryException
874    */
875   public static Node getRealNode(String strRepository,
876                                  String strWorkspace,
877                                  String strIdentifier,
878                                  boolean isWCMBase,
879                                  String cacheVisibility) throws RepositoryException {
880     LinkManager linkManager = WCMCoreUtils.getService(LinkManager.class);
881     Node selectedNode;
882     if (isWCMBase) {
883       selectedNode = getViewableNodeByComposer(strRepository,
884                                                strWorkspace,
885                                                strIdentifier,
886                                                WCMComposer.BASE_VERSION,
887                                                cacheVisibility);
888     } else {
889       selectedNode = getViewableNodeByComposer(strRepository, strWorkspace, strIdentifier, null, cacheVisibility);
890     }
891     if (selectedNode != null) {
892       if (!org.exoplatform.ecm.webui.utils.Utils.isInTrash(selectedNode)) {
893         if (linkManager.isLink(selectedNode)) {
894           if (linkManager.isTargetReachable(selectedNode)) {
895             selectedNode = linkManager.getTarget(selectedNode);
896             if (!org.exoplatform.ecm.webui.utils.Utils.isInTrash(selectedNode)) {
897               return selectedNode;
898             }
899           }
900         } else {
901           return selectedNode;
902         }
903       }
904     }
905     return null;
906   }
907 
908   public static boolean hasEditPermissionOnPage() throws Exception {
909     UIPortalApplication portalApp = Util.getUIPortalApplication();
910     UIWorkingWorkspace uiWorkingWS = portalApp.getChildById(UIPortalApplication.UI_WORKING_WS_ID);
911     UIPageBody pageBody = uiWorkingWS.findFirstComponentOfType(UIPageBody.class);
912     UIPage uiPage = (UIPage) pageBody.getUIComponent();
913     UserACL userACL = portalApp.getApplicationComponent(UserACL.class);
914 
915     if (uiPage != null) {
916       return userACL.hasEditPermissionOnPage(uiPage.getOwnerType(),
917                                              uiPage.getOwnerId(),
918                                              uiPage.getEditPermission());
919     }
920     UIPortal currentUIPortal = portalApp.<UIWorkingWorkspace> findComponentById(UIPortalApplication.UI_WORKING_WS_ID)
921     .findFirstComponentOfType(UIPortal.class);
922     UserNode currentNode = currentUIPortal.getSelectedUserNode();
923     PageKey pageReference = currentNode.getPageRef();
924     if (pageReference == null) {
925       return false;
926     }
927     UserPortalConfigService portalConfigService = portalApp.getApplicationComponent(UserPortalConfigService.class);
928     PageContext page = portalConfigService.getPage(pageReference);
929     if (page == null) {
930       return false;
931     }
932     return userACL.hasEditPermission(page);
933   }
934 
935   public static boolean hasEditPermissionOnNavigation() throws Exception {
936     UserNavigation selectedNavigation = getSelectedNavigation();
937     if(selectedNavigation == null) return false;
938     return selectedNavigation.isModifiable();
939   }
940 
941   public static boolean hasEditPermissionOnPortal() throws Exception {
942     UIPortalApplication portalApp = Util.getUIPortalApplication();
943     UIPortal currentUIPortal = portalApp.<UIWorkingWorkspace> findComponentById(UIPortalApplication.UI_WORKING_WS_ID)
944                                         .findFirstComponentOfType(UIPortal.class);
945     UserACL userACL = portalApp.getApplicationComponent(UserACL.class);
946     return userACL.hasEditPermissionOnPortal(currentUIPortal.getSiteKey().getTypeName(),
947                                              currentUIPortal.getSiteKey().getName(),
948                                              currentUIPortal.getEditPermission());
949   }
950 
951   public static UserNavigation getSelectedNavigation() throws Exception { 
952     SiteKey siteKey = Util.getUIPortal().getSiteKey();
953     return NavigationUtils.getUserNavigation(
954           Util.getPortalRequestContext().getUserPortalConfig().getUserPortal(),
955           siteKey);
956   }
957 
958   public static boolean isEmptyContent(String inputValue) {
959     boolean isEmpty = true;
960     inputValue = inputValue.trim().replaceAll("<p>", "").replaceAll("</p>", "");
961     inputValue = inputValue.replaceAll("\n", "").replaceAll("\t","");
962     inputValue = inputValue.replaceAll("&nbsp;", "");
963     if(inputValue != null && inputValue.length() > 0) return false;
964     return isEmpty;
965   }
966 
967   /**
968    * @param workspace
969    * @param strQuery
970    * @param SQLLanguage
971    * @return true as valid query, false as Invalid
972    */
973   public static boolean checkQuery(String workspace, String strQuery, String SQLLanguage) {
974     try {
975       Session session = WCMCoreUtils.getUserSessionProvider().getSession(workspace,
976             WCMCoreUtils.getService(RepositoryService.class).getCurrentRepository());
977       QueryManager qm = session.getWorkspace().getQueryManager();
978       Query query = qm.createQuery(strQuery, SQLLanguage);
979       query.execute();
980     }catch(Exception e) {
981       return false;
982     }
983     return true;
984   }
985 
986   /**
987    * get the parameter list from SQL query, the parameter have the ${PARAM} format. <br>
988    * For example:
989    * <ul>
990    *   <li>${folder-id}</li>
991    *   <li>${user}</li>
992    *   <li>${lang}</li>
993    * </ul>
994    * @param sqlQuery the given input SQL query
995    * @return a list of parameter in input SQL query
996    */
997   public static HashSet<String> getQueryParams(String sqlQuery) {
998     HashSet<String> params = new HashSet<String>();
999     if (sqlQuery == null) {
1000       return params;
1001     }
1002     Matcher matcher = Pattern.compile(SQL_PARAM_PATTERN).matcher(sqlQuery);
1003     while (matcher.find()) {
1004       String param = matcher.group();
1005       param = param.replaceAll("\\$\\{", "").replaceAll("\\}", "");
1006       params.add(param);
1007     }
1008     return params;
1009   }
1010 
1011   /**
1012    * Replace the parameter with the relevant value from <code>params</code>to
1013    * build the SQL query
1014    *
1015    * @param sqlQuery the input query that contain parameter
1016    * @param params list of all parameter(key, value) pass to the query
1017    * @return SQL query after replacing the parameter with value
1018    */
1019   public static String buildQuery(String sqlQuery, HashMap<String, String> params) {
1020     if (!hasParam(sqlQuery) || params == null || params.isEmpty()) {
1021       return sqlQuery;
1022     }
1023     String query = sqlQuery;
1024     for (String param : params.keySet()) {
1025       query = query.replaceAll("\\$\\{" + param + "\\}", params.get(param));
1026     }
1027     return query;
1028   }
1029 
1030   /**
1031    * Check if the input SQL query contains any parameter or not.
1032    *
1033    * @param sqlQuery
1034    * @return <code>false</code> if input SQL query does not contain any
1035    *         parameter <br>
1036    *         <code>true</code> if input SQL query one or more parameter
1037    */
1038   public static boolean hasParam(String sqlQuery) {
1039     if (sqlQuery == null || sqlQuery.trim().length() == 0) {
1040       return false;
1041     }
1042     if (Pattern.compile(SQL_PARAM_PATTERN).matcher(sqlQuery).find()) {
1043       return true;
1044     }
1045     return false;
1046   }
1047 
1048   /**
1049    * Get download link of a node which stored binary data
1050    * @param node Node
1051    * @return download link
1052    * @throws Exception
1053    */
1054   public static String getDownloadLink(Node node) throws Exception {
1055 
1056     if (!Utils.getRealNode(node).isNodeType(NT_FILE)) return null;
1057 
1058     // Get binary data from node
1059     DownloadService dservice = WCMCoreUtils.getService(DownloadService.class);
1060     Node jcrContentNode = node.getNode(JCR_CONTENT);
1061     InputStream input = jcrContentNode.getProperty(JCR_DATA).getStream();
1062 
1063     // Get mimeType of binary data
1064     String mimeType = jcrContentNode.getProperty(JCR_MIMETYPE).getString() ;
1065 
1066     // Make download stream
1067     InputStreamDownloadResource dresource = new InputStreamDownloadResource(input, mimeType);
1068 
1069     // Make extension part for file if it have not yet
1070     DMSMimeTypeResolver mimeTypeSolver = DMSMimeTypeResolver.getInstance();
1071     String ext = "." + mimeTypeSolver.getExtension(mimeType) ;
1072     String fileName = Utils.getRealNode(node).getName();
1073     if (fileName.lastIndexOf(ext) < 0 && !mimeTypeSolver.getMimeType(fileName).equals(mimeType)) {
1074       dresource.setDownloadName(fileName + ext);
1075     } else {
1076       dresource.setDownloadName(fileName);
1077     }
1078 
1079     return dservice.getDownloadLink(dservice.addDownloadResource(dresource)) ;
1080   }
1081 
1082   /**
1083    * Get node nt:file if node support multi-language
1084    *
1085    * @param currentNode Current Node
1086    * @return Node which has type nt:file
1087    * @throws Exception
1088    */
1089   public static Node getFileLangNode(Node currentNode) throws Exception {
1090     if(currentNode.isNodeType(NT_UNSTRUCTURED)) {
1091       if(currentNode.getNodes().getSize() > 0) {
1092         NodeIterator nodeIter = currentNode.getNodes() ;
1093         while(nodeIter.hasNext()) {
1094           Node ntFile = nodeIter.nextNode() ;
1095           if(ntFile.isNodeType(NT_FILE)) {
1096             return ntFile ;
1097           }
1098         }
1099         return currentNode ;
1100       }
1101     }
1102     return currentNode ;
1103   }
1104 
1105   /**
1106    * Allows you to add a lock token to the given node
1107    */
1108   public static void addLockToken(Node node) throws Exception {
1109     if (node.isLocked()) {
1110       String lockToken = LockUtil.getLockToken(node);
1111       if(lockToken != null) {
1112         node.getSession().addLockToken(lockToken);
1113       }
1114     }
1115   }
1116   
1117   /**
1118    * sets to lower case n first elements of string
1119    * @param st
1120    * @param n
1121    */
1122   public static String toLowerCase(String st, int n) {
1123     StringBuilder sb = new StringBuilder(st);
1124     for (int i = 0; i < n; i++) {
1125       if (i < sb.length()) {
1126         sb.setCharAt(i, Character.toLowerCase(st.charAt(i)));
1127       }
1128     }
1129     return sb.toString();
1130   }
1131   /**
1132    * 
1133    * @return true if current user is administrative user; false if current user is normal user
1134    */
1135   public static boolean isAdministratorUser() {
1136     UserACL userACL = WCMCoreUtils.getService(UserACL.class);
1137     return userACL.isUserInGroup(userACL.getAdminGroups());
1138   }
1139   
1140   public static String getProfileLink(String userId) {
1141     RequestContext ctx = RequestContext.getCurrentInstance();
1142     NodeURL nodeURL = ctx.createURL(NodeURL.TYPE);
1143     NavigationResource resource =
1144         new NavigationResource(SiteType.PORTAL, Util.getPortalRequestContext().getPortalOwner(), "profile");
1145     return nodeURL.setResource(resource).toString() + "/" + userId;
1146   }
1147 
1148   /**
1149    * Remove refences of node
1150    * @param destNode
1151    * @throws Exception
1152    */
1153   public static void removeReferences(Node destNode) throws Exception {
1154     NodeType[] mixinTypes = destNode.getMixinNodeTypes();
1155     Session session = destNode.getSession();
1156     for (int i = 0; i < mixinTypes.length; i++) {
1157       if (mixinTypes[i].getName().equals(org.exoplatform.ecm.webui.utils.Utils.EXO_CATEGORIZED)
1158               && destNode.hasProperty(org.exoplatform.ecm.webui.utils.Utils.EXO_CATEGORIZED)) {
1159         Node valueNode = null;
1160         Value valueAdd = session.getValueFactory().createValue(valueNode);
1161         destNode.setProperty(org.exoplatform.ecm.webui.utils.Utils.EXO_CATEGORIZED, new Value[] { valueAdd });
1162       }
1163     }
1164     destNode.save();
1165   }
1166 
1167 }