/*
* Copyright (C) 2003-2007 eXo Platform SAS.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see<http://www.gnu.org/licenses/>.
*/
package org.exoplatform.ecm.webui.component.explorer.sidebar ;
import java.util.HashSet;
import java.util.List;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import javax.jcr.AccessDeniedException;
import javax.jcr.Item;
import javax.jcr.ItemNotFoundException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.nodetype.NodeType;
import javax.jcr.query.Row;
import javax.portlet.PortletPreferences;
import org.apache.ws.commons.util.Base64;
import org.exoplatform.commons.utils.PageList;
import org.exoplatform.container.xml.PortalContainerInfo;
import org.exoplatform.ecm.jcr.model.Preference;
import org.exoplatform.ecm.webui.component.explorer.DocumentProviderUtils;
import org.exoplatform.ecm.webui.component.explorer.UIDocumentContainer;
import org.exoplatform.ecm.webui.component.explorer.UIDocumentWorkspace;
import org.exoplatform.ecm.webui.component.explorer.UIDrivesArea;
import org.exoplatform.ecm.webui.component.explorer.UIJCRExplorer;
import org.exoplatform.ecm.webui.component.explorer.UIJCRExplorerPortlet;
import org.exoplatform.ecm.webui.component.explorer.UIWorkingArea;
import org.exoplatform.ecm.webui.utils.JCRExceptionManager;
import org.exoplatform.services.cms.clipboard.ClipboardService;
import org.exoplatform.services.cms.documents.AutoVersionService;
import org.exoplatform.services.cms.drives.DriveData;
import org.exoplatform.services.cms.impl.Utils;
import org.exoplatform.services.cms.link.LinkManager;
import org.exoplatform.services.cms.link.LinkUtils;
import org.exoplatform.services.cms.link.NodeFinder;
import org.exoplatform.services.cms.templates.TemplateService;
import org.exoplatform.services.jcr.RepositoryService;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.services.security.ConversationState;
import org.exoplatform.services.wcm.core.NodetypeConstant;
import org.exoplatform.services.wcm.search.base.SearchDataCreator;
import org.exoplatform.services.wcm.utils.WCMCoreUtils;
import org.exoplatform.web.application.ApplicationMessage;
import org.exoplatform.web.application.RequestContext;
import org.exoplatform.webui.application.portlet.PortletRequestContext;
import org.exoplatform.webui.config.annotation.ComponentConfig;
import org.exoplatform.webui.config.annotation.EventConfig;
import org.exoplatform.webui.core.UIApplication;
import org.exoplatform.webui.core.UIComponent;
import org.exoplatform.webui.core.UIContainer;
import org.exoplatform.webui.core.UIRightClickPopupMenu;
import org.exoplatform.webui.event.Event;
import org.exoplatform.webui.event.EventListener;
import org.exoplatform.services.wcm.search.base.LazyPageList;
/**
* Created by The eXo Platform SARL
* Author : Tran The Trong
* trongtt@gmail.com
* Aug 2, 2006
*/
@ComponentConfig(
template = "app:/groovy/webui/component/explorer/sidebar/UITreeExplorer.gtmpl",
events = {
@EventConfig(listeners = UITreeExplorer.ExpandActionListener.class),
@EventConfig(listeners = UITreeExplorer.CollapseActionListener.class),
@EventConfig(listeners = UITreeExplorer.ExpandTreeActionListener.class)
}
)
public class UITreeExplorer extends UIContainer {
private class TreeNodeDataCreater implements SearchDataCreator<TreeNode>{
@Override
public TreeNode createData(Node node, Row row){
try {
return new TreeNode(node);
} catch (RepositoryException e) {
return null;
}
}
}
/**
* Logger.
*/
private static final Log LOG = ExoLogger.getLogger(UITreeExplorer.class.getName());
private TreeNode treeRoot_ ;
private String expandPath = null;
private boolean isExpand = false;
public UITreeExplorer() throws Exception {
}
public UIRightClickPopupMenu getContextMenu() {
return getAncestorOfType(UIWorkingArea.class).getChild(UIRightClickPopupMenu.class) ;
}
UIWorkingArea getWorkingArea() {
return getAncestorOfType(UIWorkingArea.class);
}
UIComponent getCustomAction() throws Exception {
return getAncestorOfType(UIWorkingArea.class).getCustomAction();
}
public TreeNode getRootTreeNode() { return treeRoot_ ; }
public String getRootActionList() throws Exception {
ClipboardService clipboardService = WCMCoreUtils.getService(ClipboardService.class);
String userId = ConversationState.getCurrent().getIdentity().getUserId();
UIJCRExplorer uiExplorer = getAncestorOfType(UIJCRExplorer.class);
if (!clipboardService.getClipboardList(userId, false).isEmpty()) {
return getContextMenu().getJSOnclickShowPopup(uiExplorer.getCurrentDriveWorkspace() + ":"
+ uiExplorer.getRootPath(),
"Paste").toString();
}
return "" ;
}
public boolean isDirectlyDrive() {
PortletPreferences portletPref =
getAncestorOfType(UIJCRExplorerPortlet.class).getPortletPreferences();
String usecase = portletPref.getValue("usecase", "").trim();
if ("selection".equals(usecase)) {
return false;
}
return true;
}
public String getDriveName() {
return getAncestorOfType(UIJCRExplorer.class).getDriveData().getName() ;
}
public String getLabel() {
RequestContext context = RequestContext.getCurrentInstance();
ResourceBundle res = context.getApplicationResourceBundle();
DriveData driveData = getAncestorOfType(UIJCRExplorer.class).getDriveData();
String id = driveData.getName();
String path = driveData.getHomePath();
try {
return res.getString("Drives.label." + id.replace(".", "").replace(" ", ""));
} catch (MissingResourceException ex) {
try {
RepositoryService repoService = WCMCoreUtils.getService(RepositoryService.class);
Node groupNode = (Node)WCMCoreUtils.getSystemSessionProvider().getSession(
repoService.getCurrentRepository().getConfiguration().getDefaultWorkspaceName(),
repoService.getCurrentRepository()).getItem(path);
return groupNode.getProperty(NodetypeConstant.EXO_LABEL).getString();
} catch(Exception e) {
return id.replace(".", " / ");
}
}
}
public boolean isAllowNodeTypesOnTree(Node node) throws RepositoryException {
DriveData currentDrive = getAncestorOfType(UIJCRExplorer.class).getDriveData();
String allowNodeTypesOnTree = currentDrive.getAllowNodeTypesOnTree();
if ((allowNodeTypesOnTree == null) || (allowNodeTypesOnTree.equals("*"))) return true;
String[] arrayAllowNodeTypesOnTree = allowNodeTypesOnTree.split(",");
for (String itemAllowNodeTypes : arrayAllowNodeTypesOnTree) {
if ((itemAllowNodeTypes.trim().length() > 0) && node.isNodeType(itemAllowNodeTypes.trim())) return true;
}
return false;
}
public String getActionsList(Node node) throws Exception {
if(node == null) return "" ;
UIJCRExplorer uiExplorer = getAncestorOfType(UIJCRExplorer.class);
try {
NodeFinder nodeFinder = getApplicationComponent(NodeFinder.class);
nodeFinder.getItem(uiExplorer.getSession(), node.getPath());
//uiExplorer.getSession().getItem(node.getPath());
return getAncestorOfType(UIWorkingArea.class).getActionsExtensionList(node) ;
} catch(PathNotFoundException pne) {
uiExplorer.refreshExplorerWithoutClosingPopup();
return "";
}
}
public List<Node> getCustomActions(Node node) throws Exception {
return getAncestorOfType(UIWorkingArea.class).getCustomActions(node) ;
}
public boolean isPreferenceNode(Node node) {
return getAncestorOfType(UIWorkingArea.class).isPreferenceNode(node) ;
}
@SuppressWarnings("unchecked")
public List<TreeNode> getRenderedChildren(TreeNode treeNode) throws Exception {
if(isPaginated(treeNode)) {
UITreeNodePageIterator pageIterator = findComponentById(treeNode.getPath());
return pageIterator.getCurrentPageData();
}
return treeNode.getChildren();
}
public boolean isSystemWorkspace() throws Exception {
return getAncestorOfType(UIJCRExplorer.class).isSystemWorkspace() ;
}
public UITreeNodePageIterator getUIPageIterator(String id) throws Exception {
return findComponentById(id);
}
public boolean isSymLink(Node node) throws RepositoryException {
LinkManager linkManager = getApplicationComponent(LinkManager.class);
return linkManager.isLink(node);
}
public String getViewTemplate(String nodeTypeName, String templateName) throws Exception {
TemplateService tempServ = getApplicationComponent(TemplateService.class) ;
return tempServ.getTemplatePath(false, nodeTypeName, templateName) ;
}
public boolean isPaginated(TreeNode treeNode) {
UIJCRExplorer jcrExplorer = getAncestorOfType(UIJCRExplorer.class) ;
int nodePerPages = jcrExplorer.getPreference().getNodesPerPage();
return (treeNode.getChildrenSize()>nodePerPages) && (findComponentById(treeNode.getPath()) != null) ;
}
public String getPortalName() {
PortalContainerInfo containerInfo = WCMCoreUtils.getService(PortalContainerInfo.class);
return containerInfo.getContainerName();
}
public String getServerPath() {
PortletRequestContext portletRequestContext = PortletRequestContext.getCurrentInstance() ;
String prefixWebDAV = portletRequestContext.getRequest().getScheme() + "://" +
portletRequestContext.getRequest().getServerName() + ":" +
String.format("%s",portletRequestContext.getRequest().getServerPort()) ;
return prefixWebDAV ;
}
public boolean isShowChildren(String path){
UIJCRExplorer jcrExplorer = getAncestorOfType(UIJCRExplorer.class);
String currentPath = jcrExplorer.getCurrentPath();
return currentPath.startsWith(path);
}
public String getRepository() {
return getAncestorOfType(UIJCRExplorer.class).getRepositoryName();
}
public String getEncodeCurrentPath() {
return encodeBase64(getAncestorOfType(UIJCRExplorer.class).getCurrentPath());
}
public String getEncodeExpandPath() {
if(expandPath != null)
return encodeBase64(expandPath);
else return null;
}
public boolean getIsExpand() {
return isExpand;
}
public static String encodeBase64(String value) {
value = value == null ? "" : value;
return Base64.encode(value.getBytes()).replaceAll(Base64.LINE_SEPARATOR,"");
}
/**
*
* @param id ID of TreeNodePageIterator, should be path of node
* @param pageList Paged list children of node
* @param selectedPath Path relate with pageList
* @param currentPath Path that user are working on
*
* */
private void addTreeNodePageIteratorAsChild(String id,
PageList<TreeNode> pageList,
String selectedPath,
String currentPath) throws Exception {
if (findComponentById(id) == null) {
UITreeNodePageIterator nodePageIterator = addChild(UITreeNodePageIterator.class, null, id);
nodePageIterator.setPageList(pageList);
nodePageIterator.setSelectedPath(selectedPath);
} else {
UITreeNodePageIterator existedComponent = findComponentById(id);
int currentPage = existedComponent.getCurrentPage();
existedComponent.setPageList(pageList);
if (!selectedPath.equalsIgnoreCase(currentPath)) {
if (currentPage <= existedComponent.getAvailablePage()) {
existedComponent.setCurrentPage(currentPage);
}
}
}
}
private Node getRootNode() throws Exception {
UIJCRExplorer uiExplorer = getAncestorOfType(UIJCRExplorer.class) ;
return uiExplorer.getRootNode();
}
private void buildTree(String path) throws Exception {
UIJCRExplorer jcrExplorer = getAncestorOfType(UIJCRExplorer.class);
int nodePerPages = jcrExplorer.getPreference().getNodesPerPage();
TreeNode treeRoot = new TreeNode(getRootNode());
if (path == null)
path = jcrExplorer.getCurrentPath();
String[] arr = path.replaceFirst(treeRoot.getPath(), "").split("/");
TreeNode temp = treeRoot;
StringBuffer subPath = null;
String rootPath = treeRoot.getPath();
StringBuffer prefix = new StringBuffer(rootPath);
if (!rootPath.equals("/")) {
prefix.append("/");
}
HashSet<String> emptySet = new HashSet<String>();//This control doesn't have any filter
//Build root tree node
if (temp.getChildrenSize() > nodePerPages) {
LazyPageList<TreeNode> pageList = DocumentProviderUtils.getInstance().getPageList(jcrExplorer.getWorkspaceName(),
rootPath,
jcrExplorer.getPreference(),
emptySet,
emptySet,
new TreeNodeDataCreater());
addTreeNodePageIteratorAsChild(treeRoot.getPath(), pageList, rootPath, path);
} else temp.setChildren(jcrExplorer.getChildrenList(rootPath, false));
//Build children
for (String nodeName : arr) {
if (nodeName.length() == 0)
continue;
temp = temp.getChildByName(nodeName);
if (temp == null) {
treeRoot_ = treeRoot;
return;
}
if (subPath == null) {
subPath = new StringBuffer();
subPath.append(prefix).append(nodeName);
} else {
subPath.append("/").append(nodeName);
}
if (temp.getChildrenSize() > nodePerPages) {
LazyPageList<TreeNode> pageList = DocumentProviderUtils.getInstance().getPageList(jcrExplorer.getWorkspaceName(),
subPath.toString(),
jcrExplorer.getPreference(),
emptySet,
emptySet,
new TreeNodeDataCreater());
addTreeNodePageIteratorAsChild(temp.getPath(), pageList, subPath.toString(), path);
} else temp.setChildren(jcrExplorer.getChildrenList(subPath.toString(), false));
}
treeRoot_ = treeRoot;
}
public void buildTree() throws Exception {
buildTree(null);
}
public boolean isDocumentNodeType(Node node) throws Exception {
TemplateService templateService = getApplicationComponent(TemplateService.class);
return templateService.isManagedNodeType(node.getPrimaryNodeType().getName());
}
public String getSelectedPath() throws Exception {
UIJCRExplorer uiExplorer = getAncestorOfType(UIJCRExplorer.class) ;
return encodeBase64(uiExplorer.getCurrentPath());
}
static public class ExpandActionListener extends EventListener<UITreeExplorer> {
public void execute(Event<UITreeExplorer> event) throws Exception {
UITreeExplorer uiTreeExplorer = event.getSource();
String path = event.getRequestContext().getRequestParameter(OBJECTID) ;
uiTreeExplorer.isExpand = false;
UIJCRExplorer uiExplorer = uiTreeExplorer.getAncestorOfType(UIJCRExplorer.class) ;
UIApplication uiApp = uiTreeExplorer.getAncestorOfType(UIApplication.class) ;
String workspaceName = event.getRequestContext().getRequestParameter("workspaceName");
Item item = null;
try {
Session session = uiExplorer.getSessionByWorkspace(workspaceName);
// Check if the path exists
NodeFinder nodeFinder = uiTreeExplorer.getApplicationComponent(NodeFinder.class);
item = nodeFinder.getItem(session, path);
} catch(PathNotFoundException pa) {
uiApp.addMessage(new ApplicationMessage("UITreeExplorer.msg.path-not-found", null,
ApplicationMessage.WARNING)) ;
return ;
} catch(ItemNotFoundException inf) {
uiApp.addMessage(new ApplicationMessage("UITreeExplorer.msg.path-not-found", null,
ApplicationMessage.WARNING)) ;
return ;
} catch(AccessDeniedException ace) {
uiApp.addMessage(new ApplicationMessage("UIDocumentInfo.msg.access-denied", null,
ApplicationMessage.WARNING)) ;
return ;
} catch(RepositoryException e) {
if (LOG.isErrorEnabled()) {
LOG.error("Repository cannot be found");
}
uiApp.addMessage(new ApplicationMessage("UITreeExplorer.msg.repository-error", null,
ApplicationMessage.WARNING)) ;
return ;
} catch (Exception e) {
JCRExceptionManager.process(uiApp, e);
return;
}
if (isInTrash(item))
return;
UIWorkingArea uiWorkingArea = uiExplorer.getChild(UIWorkingArea.class);
UIDocumentWorkspace uiDocumentWorkspace = uiWorkingArea.getChild(UIDocumentWorkspace.class);
AutoVersionService autoVersionService = WCMCoreUtils.getService(AutoVersionService.class);
if(!uiDocumentWorkspace.isRendered()) {
uiWorkingArea.getChild(UIDrivesArea.class).setRendered(false);
uiDocumentWorkspace.setRendered(true);
} else {
uiDocumentWorkspace.setRenderedChild(UIDocumentContainer.class);
}
uiExplorer.setSelectNode(workspaceName, path);
// UIDocumentContainer uiDocumentContainer = uiDocumentWorkspace.getChild(UIDocumentContainer.class);
// UIDocumentInfo uiDocumentInfo = uiDocumentContainer.getChildById("UIDocumentInfo") ;
uiExplorer.updateAjax(event);
event.getRequestContext().getJavascriptManager().
require("SHARED/multiUpload", "multiUpload").
addScripts("multiUpload.setLocation('" +
uiExplorer.getWorkspaceName() + "','" +
uiExplorer.getDriveData().getName() + "','" +
uiTreeExplorer.getLabel() + "','" +
uiExplorer.getCurrentPath() + "','" +
Utils.getPersonalDrivePath(uiExplorer.getDriveData().getHomePath(),
ConversationState.getCurrent().getIdentity().getUserId()) + "', '"+
autoVersionService.isVersionSupport(uiExplorer.getCurrentPath(), uiExplorer.getCurrentWorkspace())+"');");
}
}
private static boolean isInTrash(Item item) throws RepositoryException {
return (item instanceof Node) && Utils.isInTrash((Node) item);
}
static public class ExpandTreeActionListener extends EventListener<UITreeExplorer> {
public void execute(Event<UITreeExplorer> event) throws Exception {
UITreeExplorer uiTreeExplorer = event.getSource();
String path = event.getRequestContext().getRequestParameter(OBJECTID);
uiTreeExplorer.expandPath = path;
uiTreeExplorer.isExpand = true;
UIJCRExplorer uiExplorer = uiTreeExplorer.getAncestorOfType(UIJCRExplorer.class);
UIApplication uiApp = uiTreeExplorer.getAncestorOfType(UIApplication.class);
String workspaceName = event.getRequestContext().getRequestParameter("workspaceName");
Item item = null;
try {
Session session = uiExplorer.getSessionByWorkspace(workspaceName);
// Check if the path exists
NodeFinder nodeFinder = uiTreeExplorer.getApplicationComponent(NodeFinder.class);
item = nodeFinder.getItem(session, path);
} catch (PathNotFoundException pa) {
uiApp.addMessage(new ApplicationMessage("UITreeExplorer.msg.path-not-found",
null,
ApplicationMessage.WARNING));
return;
} catch (ItemNotFoundException inf) {
uiApp.addMessage(new ApplicationMessage("UITreeExplorer.msg.path-not-found",
null,
ApplicationMessage.WARNING));
return;
} catch (AccessDeniedException ace) {
uiApp.addMessage(new ApplicationMessage("UIDocumentInfo.msg.access-denied",
null,
ApplicationMessage.WARNING));
return;
} catch(RepositoryException e) {
if (LOG.isErrorEnabled()) {
LOG.error("Repository cannot be found");
}
uiApp.addMessage(new ApplicationMessage("UITreeExplorer.msg.repository-error", null,
ApplicationMessage.WARNING)) ;
return ;
} catch (Exception e) {
JCRExceptionManager.process(uiApp, e);
return;
}
if (isInTrash(item))
return;
if (uiExplorer.getPreference().isShowSideBar()
&& uiExplorer.getAncestorOfType(UIJCRExplorerPortlet.class).isShowSideBar()) {
uiTreeExplorer.buildTree(path);
}
}
}
static public class CollapseActionListener extends EventListener<UITreeExplorer> {
public void execute(Event<UITreeExplorer> event) throws Exception {
UITreeExplorer treeExplorer = event.getSource();
UIApplication uiApp = treeExplorer.getAncestorOfType(UIApplication.class);
try {
String path = event.getRequestContext().getRequestParameter(OBJECTID) ;
UIJCRExplorer uiExplorer = treeExplorer.getAncestorOfType(UIJCRExplorer.class) ;
path = LinkUtils.getParentPath(path) ;
uiExplorer.setSelectNode(path) ;
uiExplorer.updateAjax(event) ;
} catch(RepositoryException e) {
if (LOG.isErrorEnabled()) {
LOG.error("Repository cannot be found");
}
uiApp.addMessage(new ApplicationMessage("UITreeExplorer.msg.repository-error", null,
ApplicationMessage.WARNING)) ;
return ;
} catch (Exception e) {
JCRExceptionManager.process(uiApp, e);
return;
}
}
}
/**
* Check the node is passed have child node or not.
*
* @param node
* @return
* @throws Exception
*/
public boolean hasChildNode(Node node) throws Exception {
if(!node.hasNodes()) return false;
UIJCRExplorer uiExplorer = getAncestorOfType(UIJCRExplorer.class);
Preference preferences = uiExplorer.getPreference();
if(!isFolderType(node) && !preferences.isJcrEnable() && !node.isNodeType(org.exoplatform.ecm.webui.utils.Utils.EXO_TAXONOMY))
return false;
NodeIterator iterator = node.getNodes();
while(iterator.hasNext()) {
Node tmpNode = iterator.nextNode();
// Not allow to show hidden and non-document nodes
if (!preferences.isShowHiddenNode() && !preferences.isShowNonDocumentType()) {
if(!tmpNode.isNodeType(org.exoplatform.ecm.webui.utils.Utils.EXO_HIDDENABLE) && isDocumentOrFolderType(tmpNode))
return true;
}
// Not allow to show non-document nodes
else if (preferences.isShowHiddenNode() && !preferences.isShowNonDocumentType()) {
if(isDocumentOrFolderType(tmpNode)) return true;
}
// Not allow to show hidden nodes
else if (!preferences.isShowHiddenNode() && preferences.isShowNonDocumentType()) {
if(!tmpNode.isNodeType(org.exoplatform.ecm.webui.utils.Utils.EXO_HIDDENABLE))
return true;
}
// Allow to show hidden and non-document nodes
else return true;
}
return false;
}
/**
* Check the node is passed is a document/folder or not.
*
* @param node
* @return
* @throws Exception
*/
private boolean isDocumentOrFolderType(Node node) throws Exception {
if(node.isNodeType(org.exoplatform.ecm.webui.utils.Utils.NT_FOLDER) ||
node.isNodeType(org.exoplatform.ecm.webui.utils.Utils.NT_UNSTRUCTURED)) return true;
TemplateService templateService = getApplicationComponent(TemplateService.class);
NodeType nodeType = node.getPrimaryNodeType();
return templateService.getDocumentTemplates().contains(nodeType.getName());
}
private boolean isFolderType(Node node) throws Exception {
if(node.isNodeType(org.exoplatform.ecm.webui.utils.Utils.NT_FOLDER) ||
node.isNodeType(org.exoplatform.ecm.webui.utils.Utils.NT_UNSTRUCTURED)) return true;
return false;
}
}