View Javadoc
1   /*
2    * Copyright (C) 2003-2007 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.ecm.webui.component.explorer.control;
18  
19  import org.apache.commons.lang.StringUtils;
20  import org.exoplatform.commons.utils.CommonsUtils;
21  import org.exoplatform.ecm.jcr.SearchValidator;
22  import org.exoplatform.ecm.webui.component.explorer.*;
23  import org.exoplatform.ecm.webui.component.explorer.popup.actions.UIDocumentForm;
24  import org.exoplatform.ecm.webui.component.explorer.popup.actions.UIDocumentFormController;
25  import org.exoplatform.ecm.webui.component.explorer.search.*;
26  import org.exoplatform.portal.webui.util.Util;
27  import org.exoplatform.services.cms.BasePath;
28  import org.exoplatform.services.cms.drives.DriveData;
29  import org.exoplatform.services.cms.drives.impl.ManageDriveServiceImpl;
30  import org.exoplatform.services.cms.queries.QueryService;
31  import org.exoplatform.services.cms.views.ManageViewService;
32  import org.exoplatform.services.jcr.RepositoryService;
33  import org.exoplatform.services.jcr.ext.hierarchy.NodeHierarchyCreator;
34  import org.exoplatform.services.log.ExoLogger;
35  import org.exoplatform.services.log.Log;
36  import org.exoplatform.services.organization.OrganizationService;
37  import org.exoplatform.services.organization.User;
38  import org.exoplatform.services.security.IdentityConstants;
39  import org.exoplatform.services.wcm.core.NodeLocation;
40  import org.exoplatform.services.wcm.core.NodetypeConstant;
41  import org.exoplatform.services.wcm.utils.WCMCoreUtils;
42  import org.exoplatform.web.application.RequestContext;
43  import org.exoplatform.web.application.RequireJS;
44  import org.exoplatform.webui.config.annotation.ComponentConfig;
45  import org.exoplatform.webui.config.annotation.EventConfig;
46  import org.exoplatform.webui.core.UIComponent;
47  import org.exoplatform.webui.core.UIPopupContainer;
48  import org.exoplatform.webui.core.lifecycle.UIFormLifecycle;
49  import org.exoplatform.webui.core.model.SelectItemOption;
50  import org.exoplatform.webui.event.Event;
51  import org.exoplatform.webui.event.Event.Phase;
52  import org.exoplatform.webui.event.EventListener;
53  import org.exoplatform.webui.ext.UIExtension;
54  import org.exoplatform.webui.ext.UIExtensionManager;
55  import org.exoplatform.webui.form.UIForm;
56  import org.exoplatform.webui.form.UIFormSelectBox;
57  import org.exoplatform.webui.form.UIFormStringInput;
58  
59  import javax.jcr.Node;
60  import javax.jcr.NodeIterator;
61  import javax.jcr.PathNotFoundException;
62  import javax.jcr.RepositoryException;
63  import javax.jcr.query.Query;
64  import javax.portlet.PortletPreferences;
65  
66  import java.io.UnsupportedEncodingException;
67  import java.net.URLDecoder;
68  import java.util.*;
69  
70  /**
71   * Created by The eXo Platform SARL
72   * Author : Tran The Trong
73   *          trongtt@gmail.com
74   * Aug 2, 2006
75   */
76  @ComponentConfig(
77      lifecycle = UIFormLifecycle.class,
78      template =  "app:/groovy/webui/component/explorer/control/UIActionBar.gtmpl",
79      events = {
80        @EventConfig(listeners = UIActionBar.SearchActionListener.class, phase = Phase.DECODE),
81        @EventConfig(listeners = UIActionBar.SimpleSearchActionListener.class),
82        @EventConfig(listeners = UIActionBar.AdvanceSearchActionListener.class, phase = Phase.DECODE),
83        @EventConfig(listeners = UIActionBar.SavedQueriesActionListener.class, phase = Phase.DECODE),
84        @EventConfig(listeners = UIActionBar.ChangeTabActionListener.class, phase = Phase.DECODE),
85        @EventConfig(listeners = UIActionBar.PreferencesActionListener.class, phase = Phase.DECODE),
86        @EventConfig(listeners = UIActionBar.BackToActionListener.class, phase=Phase.DECODE),
87        @EventConfig(listeners = UIActionBar.ShowDrivesActionListener.class, phase=Phase.DECODE)
88      }
89  )
90  
91  public class UIActionBar extends UIForm {
92  
93    /**
94     * Logger.
95     */
96    private static final Log LOG  = ExoLogger.getLogger(UIActionBar.class.getName());
97  
98    private OrganizationService organizationService;
99  
100   private NodeLocation view_ ;
101   private String templateName_ ;
102   //private List<SelectItemOption<String>> tabOptions = new ArrayList<SelectItemOption<String>>() ;
103   private List<String> tabList_ = new ArrayList<String>();
104   private List<String[]> tabs_ = new ArrayList<String[]>();
105   private Map<String, String[]> actionInTabs_ = new HashMap<String, String[]>();
106 
107   private String selectedTabName_;
108 
109   final static private String   FIELD_SIMPLE_SEARCH  = "simpleSearch";
110 
111   final static private String   FIELD_ADVANCE_SEARCH = "advanceSearch";
112 
113   final static private String   FIELD_SEARCH_TYPE    = "searchType";
114 
115   final static private String   FIELD_SQL            = "SQL";
116 
117   final static private String   FIELD_XPATH          = "xPath";
118 
119   final static private String   ROOT_SQL_QUERY       = "select * from nt:base where contains(*, '$1') "
120                                                          + "order by exo:dateCreated DESC, jcr:primaryType DESC";
121 
122   final static private String   SQL_QUERY            = "select * from nt:base where jcr:path like '$0/%' and contains(*, '$1') "
123                                                          + "order by jcr:path DESC, jcr:primaryType DESC";
124 
125   private String backLink;
126 
127   public UIActionBar() throws Exception {
128     organizationService = CommonsUtils.getService(OrganizationService.class);
129 
130     addChild(new UIFormStringInput(FIELD_SIMPLE_SEARCH, FIELD_SIMPLE_SEARCH, null).addValidator(SearchValidator.class));
131     List<SelectItemOption<String>> typeOptions = new ArrayList<SelectItemOption<String>>();
132     typeOptions.add(new SelectItemOption<String>(FIELD_SQL, Query.SQL));
133     typeOptions.add(new SelectItemOption<String>(FIELD_XPATH, Query.XPATH));
134     addChild(new UIFormSelectBox(FIELD_SEARCH_TYPE, FIELD_SEARCH_TYPE, typeOptions));
135     addChild(new UIFormStringInput(FIELD_ADVANCE_SEARCH, FIELD_ADVANCE_SEARCH, null));
136   }
137 
138   public void setTabOptions(String viewName) throws Exception {
139     tabList_ = new ArrayList<String>();
140     Node viewNode = getApplicationComponent(ManageViewService.class).getViewByName(viewName,
141         WCMCoreUtils.getSystemSessionProvider());
142     view_ = NodeLocation.getNodeLocationByNode(viewNode);
143     NodeIterator tabs = viewNode.getNodes();
144     while (tabs.hasNext()) {
145       Node tab = tabs.nextNode();
146       if(!tabList_.contains(tab.getName())) tabList_.add(tab.getName());
147       setListButton(tab.getName());
148     }
149     setSelectedTab(tabList_.get(0));
150     String template = viewNode.getProperty("exo:template").getString();
151     templateName_ = template.substring(template.lastIndexOf("/") + 1);
152     UIJCRExplorer uiExplorer = getAncestorOfType(UIJCRExplorer.class);
153     uiExplorer.setRenderTemplate(template);
154   }
155   public boolean hasBackButton() {
156     String newLink = getAncestorOfType(UIJCRExplorerPortlet.class).getBacktoValue();
157     if (newLink != null && newLink.length()>0)
158       backLink = newLink;
159     return backLink != null;
160   }
161   public String getBackLink() {
162     return getAncestorOfType(UIJCRExplorerPortlet.class).getBacktoValue();
163   }
164   public String getTemplateName() { return templateName_;  }
165 
166   private void setListButton(String tabName) throws PathNotFoundException, RepositoryException {
167     
168     Node tabNode = NodeLocation.getNodeByLocation(view_).getNode(tabName);
169     if(tabNode.hasProperty("exo:buttons")) {
170       String buttons = tabNode.getProperty("exo:buttons").getString();
171       String[] buttonsInTab = StringUtils.split(buttons, ";");
172       Set<String> bt = new HashSet<String>();
173       //get all buttons in tab
174       for (String b : buttonsInTab) {
175         b = b.trim();
176         b = b.substring(0, 1).toUpperCase() + b.substring(1);
177         bt.add(b);
178       }
179       //sort the buttons by UIExtension sorting order
180       List<String> sortedButtons = new ArrayList<String>();
181       UIExtensionManager manager = getApplicationComponent(UIExtensionManager.class);
182       List<UIExtension> extensions = manager.getUIExtensions(ManageViewService.EXTENSION_TYPE);
183       for(UIExtension e : extensions) {
184         if (bt.contains(e.getName())) {
185           sortedButtons.add(e.getName().trim());
186         }
187       }
188       buttonsInTab = sortedButtons.toArray(new String[]{});
189       actionInTabs_.put(tabName, buttonsInTab);
190       tabs_.add(buttonsInTab);
191     }
192   }
193 
194   public String[] getActionInTab(String tabName) { return actionInTabs_.get(tabName); }
195 
196   public void setSelectedTab(String tabName) {
197     selectedTabName_ = tabName;
198   }
199 
200   public boolean isDirectlyDrive() {
201     PortletPreferences portletPref =
202       getAncestorOfType(UIJCRExplorerPortlet.class).getPortletPreferences();
203     String usecase =  portletPref.getValue("usecase", "").trim();
204     if ("selection".equals(usecase)) {
205       return false;
206     }
207     return true;
208   }
209 
210   public String getSelectedTab() throws Exception {
211     if(selectedTabName_ == null || selectedTabName_.length() == 0) {
212       setTabOptions(tabList_.get(0));
213       return tabList_.get(0);
214     }
215     return selectedTabName_;
216   }
217 
218   public List<String> getTabList() { return tabList_; }
219 
220   public List<Query> getSavedQueries() throws Exception {
221     String userName = Util.getPortalRequestContext().getRemoteUser();
222     return getApplicationComponent(QueryService.class).getQueries(userName, WCMCoreUtils.getSystemSessionProvider());
223   }
224 
225   public synchronized UIComponent getUIAction(String action)  {
226     try {
227       UIExtensionManager manager = getApplicationComponent(UIExtensionManager.class);
228       Map<String, Object> context = new HashMap<String, Object>();
229       UIJCRExplorer uiExplorer = getAncestorOfType(UIJCRExplorer.class);
230       Node currentNode = uiExplorer.getCurrentNode();
231       context.put(UIJCRExplorer.class.getName(), uiExplorer);
232       context.put(Node.class.getName(), currentNode);
233       return manager.addUIExtension(ManageViewService.EXTENSION_TYPE, action, context, this);
234     } catch (Exception e) {
235       if (LOG.isErrorEnabled()) {
236         LOG.error("An error occurs while checking the action", e);
237       }
238     }
239     return null;
240   }
241 
242   public boolean isActionAvailable(String tabName) {
243     List<UIComponent> listActions = new ArrayList<UIComponent>();
244     for(String action : getActionInTab(tabName)) {
245       UIComponent uicomp = getUIAction(action);
246       if(uicomp != null) listActions.add(uicomp);
247     }
248     if(listActions.size() > 0) return true;
249     return false;
250   }
251 
252   static public class SearchActionListener extends EventListener<UIActionBar> {
253     public void execute(Event<UIActionBar> event) throws Exception {
254       UIJCRExplorer uiJCRExplorer = event.getSource().getAncestorOfType(UIJCRExplorer.class);
255       UIPopupContainer UIPopupContainer = uiJCRExplorer.getChild(UIPopupContainer.class);
256       UIPopupContainer.activate(UIECMSearch.class, 700);
257       event.getRequestContext().addUIComponentToUpdateByAjax(UIPopupContainer);
258     }
259   }
260 
261   static public class SimpleSearchActionListener extends EventListener<UIActionBar> {
262     public void execute(Event<UIActionBar> event) throws Exception {
263       UIActionBar uiForm = event.getSource();
264       UIJCRExplorer uiExplorer = uiForm.getAncestorOfType(UIJCRExplorer.class);
265       String text = uiForm.getUIStringInput(FIELD_SIMPLE_SEARCH).getValue();
266       Node currentNode = uiExplorer.getCurrentNode();
267       String queryStatement = null;
268       if("/".equals(currentNode.getPath())) {
269         queryStatement = ROOT_SQL_QUERY;
270       }else {
271         queryStatement = StringUtils.replace(SQL_QUERY,"$0",currentNode.getPath());
272       }
273       queryStatement = StringUtils.replace(queryStatement,"$1", text.replaceAll("'", "''"));
274       uiExplorer.removeChildById("ViewSearch");
275       UIWorkingArea uiWorkingArea = uiExplorer.getChild(UIWorkingArea.class);
276       UIDocumentWorkspace uiDocumentWorkspace = uiWorkingArea.getChild(UIDocumentWorkspace.class);
277       if(!uiDocumentWorkspace.isRendered()) {
278         uiWorkingArea.getChild(UIDrivesArea.class).setRendered(false);
279         uiWorkingArea.getChild(UIDocumentWorkspace.class).setRendered(true);
280         uiDocumentWorkspace.setRenderedChild(UIDocumentContainer.class) ;
281       }
282       UISearchResult uiSearchResult =
283         uiDocumentWorkspace.getChildById(UIDocumentWorkspace.SIMPLE_SEARCH_RESULT);
284 
285       long startTime = System.currentTimeMillis();
286       uiSearchResult.setQuery(queryStatement, currentNode.getSession().getWorkspace().getName(), Query.SQL,
287                               IdentityConstants.SYSTEM.equals(WCMCoreUtils.getRemoteUser()), null);
288       uiSearchResult.updateGrid();
289       long time = System.currentTimeMillis() - startTime;
290 
291       uiSearchResult.setSearchTime(time);
292       uiDocumentWorkspace.setRenderedChild(UISearchResult.class);
293     }
294   }
295 
296   static public class AdvanceSearchActionListener extends EventListener<UIActionBar> {
297     public void execute(Event<UIActionBar> event) throws Exception {
298       UIJCRExplorer uiJCRExplorer = event.getSource().getAncestorOfType(UIJCRExplorer.class);
299       UIPopupContainer UIPopupContainer = uiJCRExplorer.getChild(UIPopupContainer.class);
300       UIECMSearch uiECMSearch = event.getSource().createUIComponent(UIECMSearch.class, null, null);
301       UIContentNameSearch contentNameSearch = uiECMSearch.findFirstComponentOfType(UIContentNameSearch.class);
302       String currentNodePath = uiJCRExplorer.getCurrentNode().getPath();
303       contentNameSearch.setLocation(currentNodePath);
304       UISimpleSearch uiSimpleSearch = uiECMSearch.findFirstComponentOfType(UISimpleSearch.class);
305       uiSimpleSearch.getUIFormInputInfo(UISimpleSearch.NODE_PATH).setValue(currentNodePath);
306       UIPopupContainer.activate(uiECMSearch, 700, 500);
307       event.getRequestContext().addUIComponentToUpdateByAjax(UIPopupContainer);
308     }
309   }
310   static public class BackToActionListener extends EventListener<UIActionBar> {
311       public void execute(Event<UIActionBar> event) throws Exception {
312         UIJCRExplorer uiExplorer = event.getSource().getAncestorOfType(UIJCRExplorer.class);
313           UIWorkingArea uiWorkingArea = uiExplorer.getChild(UIWorkingArea.class);
314           UIDocumentWorkspace uiDocumentWorkspace = uiWorkingArea.getChild(UIDocumentWorkspace.class);
315           UIDocumentFormController uiDocumentFormController =  uiDocumentWorkspace.getChild(UIDocumentFormController.class);
316           String backLink = event.getSource().getBackLink();
317           if (uiDocumentFormController != null) {
318             UIDocumentForm uiDocument = uiDocumentFormController.getChild(UIDocumentForm.class);
319           if (uiDocument!=null) {
320             uiDocument.releaseLock();
321           }
322             uiDocumentWorkspace.removeChild(UIDocumentFormController.class);
323           } else
324           uiExplorer.cancelAction();
325           RequireJS requireJS = event.getRequestContext().getJavascriptManager().getRequireJS();
326           requireJS.require("SHARED/ecm-utils", "ecmutil").addScripts("ecmutil.ECMUtils.ajaxRedirect('" + backLink + "');");
327       }
328     }
329   static public class SavedQueriesActionListener extends EventListener<UIActionBar> {
330     public void execute(Event<UIActionBar> event) throws Exception {
331       UIJCRExplorer uiJCRExplorer = event.getSource().getAncestorOfType(UIJCRExplorer.class);
332       UIPopupContainer UIPopupContainer = uiJCRExplorer.getChild(UIPopupContainer.class);
333       UISavedQuery uiSavedQuery = event.getSource().createUIComponent(UISavedQuery.class, null, null);
334       uiSavedQuery.setIsQuickSearch(true);
335       uiSavedQuery.updateGrid(1);
336       UIPopupContainer.activate(uiSavedQuery, 700, 400);
337       event.getRequestContext().addUIComponentToUpdateByAjax(UIPopupContainer);
338     }
339   }
340 
341   static public class ChangeTabActionListener extends EventListener<UIActionBar> {
342     public void execute(Event<UIActionBar> event) throws Exception {
343       UIActionBar uiActionBar = event.getSource();
344       String selectedTabName = event.getRequestContext().getRequestParameter(OBJECTID);
345       uiActionBar.setSelectedTab(selectedTabName);
346       event.getRequestContext().addUIComponentToUpdateByAjax(uiActionBar.getAncestorOfType(UIJCRExplorer.class));
347     }
348   }
349 
350   static public class PreferencesActionListener extends EventListener<UIActionBar> {
351     public void execute(Event<UIActionBar> event) throws Exception {
352       UIActionBar uiActionBar = event.getSource();
353       UIJCRExplorer uiJCRExplorer = uiActionBar.getAncestorOfType(UIJCRExplorer.class);
354       UIPopupContainer popupAction = uiJCRExplorer.getChild(UIPopupContainer.class);
355       UIPreferencesForm uiPrefForm = popupAction.activate(UIPreferencesForm.class,600) ;
356       uiPrefForm.update(uiJCRExplorer.getPreference()) ;
357       event.getRequestContext().addUIComponentToUpdateByAjax(popupAction) ;
358     }
359   }
360 
361   static public class ShowDrivesActionListener extends EventListener<UIActionBar> {
362     public void execute(Event<UIActionBar> event) throws Exception {
363       UIJCRExplorer uiExplorer = event.getSource().getAncestorOfType(UIJCRExplorer.class);
364       UIWorkingArea uiWorkingArea = uiExplorer.getChild(UIWorkingArea.class);
365       UIDrivesArea uiDriveArea = uiWorkingArea.getChild(UIDrivesArea.class);
366       if (uiDriveArea.isRendered()) {
367         uiDriveArea.setRendered(false);
368         uiWorkingArea.getChild(UIDocumentWorkspace.class).setRendered(true);
369       } else {
370         uiDriveArea.setRendered(true);
371         uiWorkingArea.getChild(UIDocumentWorkspace.class).setRendered(false);
372       }
373       event.getRequestContext().addUIComponentToUpdateByAjax(uiWorkingArea) ;
374     }
375   }
376 
377   public String getDriveLabel() {
378     RequestContext context = RequestContext.getCurrentInstance();
379     ResourceBundle res = context.getApplicationResourceBundle();
380     DriveData drive = getAncestorOfType(UIJCRExplorer.class).getDriveData();
381     String driveName = drive.getName();
382 
383     String driveLabel = "";
384 
385     try {
386       if(ManageDriveServiceImpl.GROUPS_DRIVE_NAME.equals(driveName) || driveName.startsWith(".")) {
387         // Groups drive
388         RepositoryService repoService = WCMCoreUtils.getService(RepositoryService.class);
389         NodeHierarchyCreator nodeHierarchyCreator = WCMCoreUtils.getService(NodeHierarchyCreator.class);
390         String groupPath = nodeHierarchyCreator.getJcrPath(BasePath.CMS_GROUPS_PATH);
391         Node groupNode = (Node)WCMCoreUtils.getSystemSessionProvider().getSession(
392                 repoService.getCurrentRepository().getConfiguration().getDefaultWorkspaceName(),
393                 repoService.getCurrentRepository()).getItem(
394                 groupPath + drive.getName().replace(".", "/"));
395         driveLabel = groupNode.getProperty(NodetypeConstant.EXO_LABEL).getString();
396       } else if(ManageDriveServiceImpl.USER_DRIVE_NAME.equals(driveName)) {
397         // User Documents drive
398         String userDisplayName = "";
399         String driveLabelKey = "Drives.label.UserDocuments";
400         String userIdPath = drive.getParameters().get(ManageDriveServiceImpl.DRIVE_PARAMATER_USER_ID);
401         String userId = userIdPath != null ? userIdPath.substring(userIdPath.lastIndexOf("/") + 1) : null;
402         if(StringUtils.isNotEmpty(userId)) {
403           userDisplayName = userId;
404           User user = organizationService.getUserHandler().findUserByName(userId);
405           if(user != null) {
406             userDisplayName = user.getDisplayName();
407           }
408         }
409         try {
410           driveLabel = res.getString(driveLabelKey).replace("{0}", userDisplayName);
411         } catch(MissingResourceException mre) {
412           LOG.error("Cannot get resource string " + driveLabel + " : " + mre.getMessage(), mre);
413           driveLabel = userDisplayName;
414         }
415       } else {
416         // Others drives
417         String driveLabelKey = "Drives.label." + driveName.replace(".", "").replace(" ", "");
418         try {
419           driveLabel = res.getString(driveLabelKey);
420         } catch (MissingResourceException ex) {
421           //
422           driveLabel = driveName.replace(".", "/");
423         }
424       }
425     } catch(Exception e) {
426       driveLabel = driveName.replace(".", " / ");
427     }
428 
429     return driveLabel;
430   }
431 }