/*
* Copyright (C) 2003-2008 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.rightclick.manager;
import org.apache.commons.lang.StringEscapeUtils;
import org.exoplatform.ecm.webui.component.explorer.UIJCRExplorer;
import org.exoplatform.ecm.webui.component.explorer.UIWorkingArea;
import org.exoplatform.ecm.webui.component.explorer.control.filter.*;
import org.exoplatform.ecm.webui.component.explorer.control.listener.UIWorkingAreaActionListener;
import org.exoplatform.ecm.webui.component.explorer.popup.actions.UISelectRestorePath;
import org.exoplatform.ecm.webui.utils.JCRExceptionManager;
import org.exoplatform.ecm.webui.utils.Utils;
import org.exoplatform.services.cms.documents.TrashService;
import org.exoplatform.services.cms.link.LinkManager;
import org.exoplatform.services.cms.link.NodeFinder;
import org.exoplatform.services.jcr.RepositoryService;
import org.exoplatform.services.jcr.core.ManageableRepository;
import org.exoplatform.services.jcr.ext.common.SessionProvider;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.services.wcm.utils.WCMCoreUtils;
import org.exoplatform.web.application.ApplicationMessage;
import org.exoplatform.web.application.RequestContext;
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.UIPopupContainer;
import org.exoplatform.webui.event.Event;
import org.exoplatform.webui.ext.filter.UIExtensionFilter;
import org.exoplatform.webui.ext.filter.UIExtensionFilters;
import org.exoplatform.webui.ext.manager.UIAbstractManager;
import org.exoplatform.webui.ext.manager.UIAbstractManagerComponent;
import javax.jcr.AccessDeniedException;
import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.Session;
import javax.jcr.lock.LockException;
import javax.jcr.nodetype.ConstraintViolationException;
import javax.jcr.version.VersionException;
import javax.portlet.PortletPreferences;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.ResourceBundle;
import java.util.regex.Matcher;
/**
* Created by The eXo Platform SARL
* Author : Nguyen Anh Vu
* anhvurz90@gmail.com
* Oct 14, 2009
* 5:24:01 PM
*/
@ComponentConfig(
events = {
@EventConfig(listeners = RestoreFromTrashManageComponent.RestoreFromTrashActionListener.class)
}
)
public class RestoreFromTrashManageComponent extends UIAbstractManagerComponent {
private static final List<UIExtensionFilter> FILTERS
= Arrays.asList(new UIExtensionFilter[] { new IsInTrashFilter(),
new IsNotLockedFilter(),
new IsCheckedOutFilter(),
new HasRemovePermissionFilter(),
new IsAbleToRestoreFilter(),
new IsNotTrashHomeNodeFilter() });
private final static Log LOG = ExoLogger.getLogger(RestoreFromTrashManageComponent.class.getName());
private static int numberItemsRestored = 0;
private static String itemName = "";
@UIExtensionFilters
public List<UIExtensionFilter> getFilters() {
return FILTERS;
}
private static void restoreFromTrash(String srcPath, Event<RestoreFromTrashManageComponent> event) throws Exception {
UIWorkingArea uiWorkingArea = event.getSource().getParent();
UIJCRExplorer uiExplorer = uiWorkingArea.getAncestorOfType(UIJCRExplorer.class);
UIApplication uiApp = uiWorkingArea.getAncestorOfType(UIApplication.class);
Matcher matcher = UIWorkingArea.FILE_EXPLORER_URL_SYNTAX.matcher(srcPath);
String wsName;
Node node;
if (matcher.find()) {
wsName = matcher.group(1);
srcPath = matcher.group(2);
} else {
throw new IllegalArgumentException("The ObjectId is invalid '"+ srcPath + "'");
}
Session session = uiExplorer.getSessionByWorkspace(wsName);
try {
// Use the method getNodeByPath because it is link aware
node = uiExplorer.getNodeByPath(srcPath, session, false);
//return false if the target is already deleted
if ( Utils.targetNodeAndLinkInTrash(node) ) {
return;
}
// Reset the path to manage the links that potentially create virtual path
srcPath = node.getPath();
} catch(PathNotFoundException path) {
uiApp.addMessage(new ApplicationMessage("UIPopupMenu.msg.path-not-found-exception",
null,ApplicationMessage.WARNING));
return;
}
confirmToRestore(node, srcPath, event);
}
private static void confirmToRestore(Node node, String srcPath, Event<RestoreFromTrashManageComponent> event) throws Exception {
UIWorkingArea uiWorkingArea = event.getSource().getParent();
UIJCRExplorer uiExplorer = uiWorkingArea.getAncestorOfType(UIJCRExplorer.class);
itemName = Utils.getTitle(node);
String restorePath = node.getProperty(Utils.EXO_RESTOREPATH).getString();
String restoreWs = node.getProperty(Utils.EXO_RESTORE_WORKSPACE).getString();
Session session = uiExplorer.getSessionByWorkspace(restoreWs);
NodeFinder nodeFinder = uiExplorer.getApplicationComponent(NodeFinder.class);
try {
nodeFinder.getItem(session, restorePath);
} catch (PathNotFoundException e) {
doRestore(srcPath, node, event);
numberItemsRestored++;
return;
}
doRestore(srcPath, node, event);
numberItemsRestored++;
}
public static void doRestore(String srcPath, Node node, Event<? extends UIComponent> event) throws Exception {
UIJCRExplorer uiExplorer = event.getSource().getAncestorOfType(UIJCRExplorer.class);
UIWorkingArea uiWorkingArea = event.getSource().getParent();
TrashService trashService = WCMCoreUtils.getService(TrashService.class);
UIApplication uiApp = event.getSource().getAncestorOfType(UIApplication.class);
try {
uiExplorer.addLockToken(node);
} catch (Exception e) {
JCRExceptionManager.process(uiApp, e);
return;
}
SessionProvider sessionProvider = null;
try {
PortletPreferences portletPrefs = uiExplorer.getPortletPreferences();
String repository = uiExplorer.getRepositoryName();
String trashWorkspace = portletPrefs.getValue(Utils.TRASH_WORKSPACE, "");
String trashHomeNodePath = portletPrefs.getValue(Utils.TRASH_HOME_NODE_PATH, "");
//Have to create session from System Provider to allow normal user to restore the content that deleted before
sessionProvider = WCMCoreUtils.getSystemSessionProvider();
RepositoryService repositoryService = uiExplorer.getApplicationComponent(RepositoryService.class);
ManageableRepository manageableRepository = repositoryService.getCurrentRepository();
Session trashSession = sessionProvider.getSession(trashWorkspace, manageableRepository);
Node trashHomeNode = (Node) trashSession.getItem(trashHomeNodePath);
try {
trashService.restoreFromTrash(srcPath, sessionProvider);
// delete symlink after target node
LinkManager linkManager = WCMCoreUtils.getService(LinkManager.class);
List<Node> symlinks = linkManager.getAllLinks(node, org.exoplatform.services.cms.impl.Utils.EXO_SYMLINK);
for (Node symlink : symlinks) {
String realPath = symlink.getPath();
if(!trashHomeNode.getSession().itemExists(realPath)){
realPath = trashHomeNodePath + "/" + symlink.getName();
}
trashService.restoreFromTrash(realPath, sessionProvider);
}
uiExplorer.updateAjax(event);
} catch(PathNotFoundException e) {
UIPopupContainer uiPopupContainer = uiExplorer.getChild(UIPopupContainer.class);
UISelectRestorePath uiSelectRestorePath =
uiWorkingArea.createUIComponent(UISelectRestorePath.class, null, null);
uiSelectRestorePath.setTrashHomeNode(trashHomeNode);
uiSelectRestorePath.setSrcPath(srcPath);
uiSelectRestorePath.setRepository(repository);
uiPopupContainer.activate(uiSelectRestorePath, 600, 300);
event.getRequestContext().addUIComponentToUpdateByAjax(uiPopupContainer);
}
} catch (PathNotFoundException e) {
if (LOG.isErrorEnabled()) {
LOG.error("Path not found! Maybe, it was removed or path changed, can't restore node :" + node.getPath());
}
JCRExceptionManager.process(uiApp, e);
uiExplorer.updateAjax(event);
} catch (LockException e) {
if (LOG.isErrorEnabled()) {
LOG.error("node is locked, can't restore node :" + node.getPath());
}
JCRExceptionManager.process(uiApp, e);
uiExplorer.updateAjax(event);
} catch (VersionException e) {
if (LOG.isErrorEnabled()) {
LOG.error("node is checked in, can't restore node:" + node.getPath());
}
JCRExceptionManager.process(uiApp, e);
uiExplorer.updateAjax(event);
} catch (AccessDeniedException e) {
if (LOG.isErrorEnabled()) {
LOG.error("access denied, can't restore of node:" + node.getPath());
}
JCRExceptionManager.process(uiApp, e);
uiExplorer.updateAjax(event);
} catch (ConstraintViolationException e) {
if (LOG.isErrorEnabled()) {
LOG.error("access denied, can't restore of node:" + node.getPath());
}
JCRExceptionManager.process(uiApp, e);
uiExplorer.updateAjax(event);
} catch (Exception e) {
if (LOG.isErrorEnabled()) {
LOG.error("an unexpected error occurs", e);
}
JCRExceptionManager.process(uiApp, e);
uiExplorer.updateAjax(event);
}
}
public static class RestoreFromTrashActionListener extends UIWorkingAreaActionListener<RestoreFromTrashManageComponent> {
public void restoreFromTrashManage(Event<RestoreFromTrashManageComponent> event) throws Exception {
numberItemsRestored = 0;
String srcPath = event.getRequestContext().getRequestParameter(OBJECTID);
if (srcPath.indexOf(';') > -1) {
multiRestoreFromTrash(srcPath.split(";"), event);
} else {
restoreFromTrash(srcPath, event);
}
RequestContext context = RequestContext.getCurrentInstance();
ResourceBundle res = context.getApplicationResourceBundle();
String restoreNotice = "";
if(!srcPath.contains(";") && numberItemsRestored == 1) {
restoreNotice = "UIWorkingArea.msg.feedback-restore";
restoreNotice = res.getString(restoreNotice);
restoreNotice = restoreNotice.replace("{" + 0 + "}", itemName);
} else if(srcPath.indexOf(';') > -1 && numberItemsRestored >= 1) {
restoreNotice = "UIWorkingArea.msg.feedback-restore-multi";
restoreNotice = res.getString(restoreNotice);
restoreNotice = restoreNotice.replace("{" + 0 + "}", String.valueOf(numberItemsRestored));
}
restoreNotice = restoreNotice.replace("\"", "'");
restoreNotice = StringEscapeUtils.escapeHtml(restoreNotice);
if(restoreNotice.length() > 0) {
UIWorkingArea uiWorkingArea = event.getSource().getParent();
uiWorkingArea.setWCMNotice(restoreNotice);
}
}
private void multiRestoreFromTrash(String[] paths, Event<RestoreFromTrashManageComponent> event) throws Exception {
UIJCRExplorer uiExplorer = event.getSource().getAncestorOfType(UIJCRExplorer.class);
Session session;
Matcher matcher;
String wsName;
Node node;
String origialPath;
Arrays.sort(paths,Collections.reverseOrder());
List<String> newPaths = new ArrayList<String>();
// In case multi checked items, check if a Symlink node is with its Target in Trash or not.
for (int i = 0; i < paths.length ; i++) {
String srcPath = paths[i];
origialPath = srcPath;
matcher = UIWorkingArea.FILE_EXPLORER_URL_SYNTAX.matcher(srcPath);
if (matcher.find()) {
wsName = matcher.group(1);
srcPath = matcher.group(2);
} else {
throw new IllegalArgumentException("The ObjectId is invalid '" + srcPath + "'");
}
try {
session = uiExplorer.getSessionByWorkspace(wsName);
// Use the method getNodeByPath because it is link aware
node = uiExplorer.getNodeByPath(srcPath, session, false);
// Not allow to restore multi items if there is a symlink node, which have Target-In-Trash, in items list.
// program returns at once.
if (Utils.targetNodeAndLinkInTrash(node)) {
continue;
}
// Reset the path to manage the links that potentially create virtual
newPaths.add(origialPath);
} catch (PathNotFoundException path) {
return;
}
}
for (String path : newPaths) {
if (acceptForMultiNode(event, path))
restoreFromTrash(path, event);
}
}
public void processEvent(Event<RestoreFromTrashManageComponent> event) throws Exception {
restoreFromTrashManage(event);
}
}
@Override
public Class<? extends UIAbstractManager> getUIAbstractManagerClass() {
return null;
}
}