View Javadoc
1   /***************************************************************************
2    * Copyright (C) 2003-2009 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   **************************************************************************/
18  package org.exoplatform.ecm.webui.component.explorer.rightclick.manager;
19  
20  import org.apache.commons.lang.BooleanUtils;
21  import org.apache.commons.lang.StringUtils;
22  import org.exoplatform.ecm.utils.lock.LockUtil;
23  import org.exoplatform.ecm.webui.component.explorer.UIDocumentAutoVersionForm;
24  import org.exoplatform.ecm.webui.component.explorer.UIDocumentInfo;
25  import org.exoplatform.ecm.webui.component.explorer.UIJCRExplorer;
26  import org.exoplatform.ecm.webui.component.explorer.UIWorkingArea;
27  import org.exoplatform.ecm.webui.component.explorer.control.filter.IsNotInTrashFilter;
28  import org.exoplatform.ecm.webui.component.explorer.control.filter.IsNotNtFileFilter;
29  import org.exoplatform.ecm.webui.component.explorer.control.filter.IsNotTrashHomeNodeFilter;
30  import org.exoplatform.ecm.webui.component.explorer.control.filter.IsPasteableFilter;
31  import org.exoplatform.ecm.webui.component.explorer.control.listener.UIWorkingAreaActionListener;
32  import org.exoplatform.ecm.webui.component.explorer.sidebar.UITreeExplorer;
33  import org.exoplatform.ecm.webui.component.explorer.sidebar.UITreeNodePageIterator;
34  import org.exoplatform.ecm.webui.utils.JCRExceptionManager;
35  import org.exoplatform.ecm.webui.utils.PermissionUtil;
36  import org.exoplatform.ecm.webui.utils.Utils;
37  import org.exoplatform.services.cms.actions.ActionServiceContainer;
38  import org.exoplatform.services.cms.clipboard.ClipboardService;
39  import org.exoplatform.services.cms.clipboard.jcr.model.ClipboardCommand;
40  import org.exoplatform.services.cms.documents.AutoVersionService;
41  import org.exoplatform.services.cms.documents.TrashService;
42  import org.exoplatform.services.cms.jcrext.activity.ActivityCommonService;
43  import org.exoplatform.services.cms.link.LinkUtils;
44  import org.exoplatform.services.cms.relations.RelationsService;
45  import org.exoplatform.services.cms.thumbnail.ThumbnailService;
46  import org.exoplatform.services.listener.ListenerService;
47  import org.exoplatform.services.log.ExoLogger;
48  import org.exoplatform.services.log.Log;
49  import org.exoplatform.services.security.ConversationState;
50  import org.exoplatform.services.wcm.core.NodetypeConstant;
51  import org.exoplatform.services.wcm.utils.WCMCoreUtils;
52  import org.exoplatform.web.application.ApplicationMessage;
53  import org.exoplatform.webui.config.annotation.ComponentConfig;
54  import org.exoplatform.webui.config.annotation.EventConfig;
55  import org.exoplatform.webui.core.UIApplication;
56  import org.exoplatform.webui.core.UIPageIterator;
57  import org.exoplatform.webui.core.UIPopupContainer;
58  import org.exoplatform.webui.core.UIPopupWindow;
59  import org.exoplatform.webui.event.Event;
60  import org.exoplatform.webui.exception.MessageException;
61  import org.exoplatform.webui.ext.filter.UIExtensionFilter;
62  import org.exoplatform.webui.ext.filter.UIExtensionFilters;
63  import org.exoplatform.webui.ext.manager.UIAbstractManager;
64  import org.exoplatform.webui.ext.manager.UIAbstractManagerComponent;
65  
66  import javax.jcr.AccessDeniedException;
67  import javax.jcr.ItemExistsException;
68  import javax.jcr.ItemNotFoundException;
69  import javax.jcr.LoginException;
70  import javax.jcr.Node;
71  import javax.jcr.PathNotFoundException;
72  import javax.jcr.Property;
73  import javax.jcr.PropertyIterator;
74  import javax.jcr.Session;
75  import javax.jcr.Value;
76  import javax.jcr.Workspace;
77  import javax.jcr.lock.LockException;
78  import javax.jcr.nodetype.ConstraintViolationException;
79  import javax.jcr.nodetype.NodeType;
80  import javax.jcr.version.VersionException;
81  
82  import java.util.ArrayList;
83  import java.util.Arrays;
84  import java.util.HashMap;
85  import java.util.HashSet;
86  import java.util.List;
87  import java.util.Map;
88  import java.util.Set;
89  import java.util.regex.Matcher;
90  
91  /**
92   * Created by The eXo Platform SARL Author : Hoang Van Hung hunghvit@gmail.com
93   * Aug 6, 2009
94   */
95  
96  @ComponentConfig(
97      events = {
98        @EventConfig(listeners = PasteManageComponent.PasteActionListener.class)
99      }
100 )
101 
102 public class PasteManageComponent extends UIAbstractManagerComponent {
103 
104   private static final Log    LOG           = ExoLogger.getLogger(PasteManageComponent.class.getName());
105 
106   private static final List<UIExtensionFilter> FILTERS = Arrays.asList(new IsNotInTrashFilter(),
107                                               new IsPasteableFilter(),
108                                               new IsNotNtFileFilter(),
109                                               new IsNotTrashHomeNodeFilter());
110 
111   private static final String RELATION_PROP = "exo:relation";
112 
113   private static boolean isRefresh = true;
114   private static Map<String, Boolean> versionedRemember = new HashMap<>();
115   private static Map<String, Boolean> nonVersionedRemember = new HashMap<>();
116 
117   public static boolean isIsRefresh() {
118     return isRefresh;
119   }
120 
121   @UIExtensionFilters
122   public List<UIExtensionFilter> getFilters() {
123     return FILTERS;
124   }
125 
126   public static void pasteManage(Event<PasteManageComponent> event, UIJCRExplorer uiExplorer)
127       throws Exception {
128     ClipboardService clipboardService = WCMCoreUtils.getService(ClipboardService.class);
129     String userId = ConversationState.getCurrent().getIdentity().getUserId();
130     AutoVersionService autoVersionService = WCMCoreUtils.getService(AutoVersionService.class);
131     UIWorkingArea uiWorkingArea = event.getSource().getParent();
132     String destPath = event.getRequestContext().getRequestParameter(OBJECTID);
133     String nodePath = null;
134     Session session = null;
135     if (destPath != null) {
136       Matcher matcher = UIWorkingArea.FILE_EXPLORER_URL_SYNTAX.matcher(destPath);
137       String wsName = null;
138       if (matcher.find()) {
139         wsName = matcher.group(1);
140         nodePath = matcher.group(2);
141         session = uiExplorer.getSessionByWorkspace(wsName);
142       } else {
143         throw new IllegalArgumentException("The ObjectId is invalid '" + destPath + "'");
144       }
145     }
146     UIApplication uiApp = uiExplorer.getAncestorOfType(UIApplication.class);
147     if (clipboardService.getClipboardList(userId, false).size() < 1) {
148       uiApp.addMessage(new ApplicationMessage("UIPopupMenu.msg.no-node", null,
149           ApplicationMessage.WARNING));
150 
151       return;
152     }
153     Node destNode;
154     try {
155       // Use the method getNodeByPath because it is link aware
156       destNode = destPath == null ? uiExplorer.getCurrentNode() : uiExplorer.getNodeByPath(
157           nodePath, session);
158       // Reset the session to manage the links that potentially change of
159       // workspace
160       session = destNode.getSession();
161       if (destPath == null) {
162         destPath = session.getWorkspace().getName() + ":" + destNode.getPath();
163       }
164     } catch (PathNotFoundException path) {
165       uiApp.addMessage(new ApplicationMessage("UIPopupMenu.msg.path-not-found-exception", null,
166           ApplicationMessage.WARNING));
167 
168       return;
169     } catch (Exception e) {
170       JCRExceptionManager.process(uiApp, e);
171       return;
172     }
173     if (!PermissionUtil.canAddNode(destNode)) {
174       uiApp.addMessage(new ApplicationMessage("UIPopupMenu.msg.can-not-paste-node", null,
175           ApplicationMessage.WARNING));
176 
177       uiExplorer.updateAjax(event);
178       return;
179     }
180     if (uiExplorer.nodeIsLocked(destNode)) {
181       Object[] arg = { destPath };
182       uiApp.addMessage(new ApplicationMessage("UIPopupMenu.msg.node-locked", arg,
183           ApplicationMessage.WARNING));
184 
185       return;
186     }
187     if (!destNode.isCheckedOut()) {
188       uiApp.addMessage(new ApplicationMessage("UIActionBar.msg.node-checkedin", null));
189 
190       return;
191     }
192     String currentPath = uiExplorer.getCurrentNode().getPath();
193     ClipboardCommand clipboardCommand = clipboardService.getLastClipboard(userId);
194     try {
195       if (clipboardCommand!=null && clipboardService.getClipboardList(userId, true).isEmpty()) {
196         processPaste(clipboardCommand, destNode, event, uiExplorer);
197       } else {
198         if(autoVersionService.isVersionSupport(destNode.getPath(), destNode.getSession().getWorkspace().getName())) {
199           processPasteMultiple(destNode, event, uiExplorer);
200         }else{
201           processPasteMultiple(destPath, event, uiExplorer);
202         }
203       }
204     } catch (PathNotFoundException pe) {
205       uiApp.addMessage(new ApplicationMessage("UIPopupMenu.msg.cannot-readsource", null));
206 
207       return;
208     }
209     //session.save();
210 
211 
212     // Get paginator of UITreeExplorer && UIDocumentInfo
213     UITreeNodePageIterator extendedPageIterator = null;
214     UITreeExplorer uiTreeExplorer = uiExplorer.findFirstComponentOfType(UITreeExplorer.class);
215     if (uiTreeExplorer != null) {
216       extendedPageIterator = uiTreeExplorer.getUIPageIterator(currentPath);
217     }
218     UIPageIterator contentPageIterator = uiExplorer.findComponentById(UIDocumentInfo.CONTENT_PAGE_ITERATOR_ID);
219 
220     // Get current page index
221     int currentPage = 1;
222     if (contentPageIterator != null) {
223       currentPage = contentPageIterator.getCurrentPage();
224     }
225 
226     if(isRefresh) {
227       // Rebuild screen after pasting new content
228       versionedRemember.clear();
229       nonVersionedRemember.clear();
230       uiExplorer.updateAjax(event);
231     }
232 
233     // Because after updateAjax, paginator automatically set to first page then we need set again current pageindex
234     if (contentPageIterator != null) {
235       contentPageIterator.setCurrentPage(currentPage);
236     }
237     if (extendedPageIterator != null) {
238       extendedPageIterator.setCurrentPage(currentPage);
239     }
240   }
241 
242   public static void processPaste(ClipboardCommand clipboardCommand, Node destNode, Event<?> event, UIJCRExplorer uiExplorer)
243     throws Exception{
244     AutoVersionService autoVersionService = WCMCoreUtils.getService(AutoVersionService.class);
245     Node sourceNode = (Node)uiExplorer.getSessionByWorkspace(clipboardCommand.getWorkspace()).
246             getItem(clipboardCommand.getSrcPath());
247     if(destNode.hasNode(sourceNode.getName()) && sourceNode.isNodeType(NodetypeConstant.NT_FILE)
248             && autoVersionService.isVersionSupport(destNode.getPath(), destNode.getSession().getWorkspace().getName())){
249       Set<ClipboardCommand> clipboardCommands = new HashSet<>();
250       clipboardCommands.add(clipboardCommand);
251       showConfirmDialog(destNode, sourceNode, uiExplorer, clipboardCommand, clipboardCommands, event);
252     }else {
253       processPaste(clipboardCommand, destNode.getPath(),uiExplorer, event, false, true);
254     }
255   }
256 
257   private static void processPasteMultiple(String destPath, Event<?> event, UIJCRExplorer uiExplorer)
258           throws Exception {
259     ClipboardService clipboardService = WCMCoreUtils.getService(ClipboardService.class);
260     String userId = ConversationState.getCurrent().getIdentity().getUserId();
261     int pasteNum = 0;
262     Set<ClipboardCommand> virtualClipboards = clipboardService.getClipboardList(userId, true);
263     for (ClipboardCommand clipboard : virtualClipboards) {
264       pasteNum++;
265       if (pasteNum == virtualClipboards.size()) {
266         processPaste(clipboard, destPath, uiExplorer, event, true, true);
267         break;
268       }
269       processPaste(clipboard, destPath, uiExplorer, event, true, false);
270     }
271   }
272 
273   private static void processPasteMultiple(Node destNode, Event<?> event, UIJCRExplorer uiExplorer)
274       throws Exception {
275     ClipboardService clipboardService = WCMCoreUtils.getService(ClipboardService.class);
276     String userId = ConversationState.getCurrent().getIdentity().getUserId();
277     Set<ClipboardCommand> virtualClipboards = clipboardService.getClipboardList(userId, true);
278 
279     processPasteMultiple(destNode, event, uiExplorer, virtualClipboards, null);
280   }
281 
282   public static void processPasteMultiple(Node destNode, Event<?> event, UIJCRExplorer uiExplorer,
283                                           Set<ClipboardCommand> virtualClipboards, String action) throws Exception{
284     int pasteNum = 0;
285     Set<ClipboardCommand> _virtualClipboards = new HashSet<>(virtualClipboards);
286     Set<ClipboardCommand> processList = new HashSet<>(virtualClipboards);
287     UIApplication uiApp = uiExplorer.getAncestorOfType(UIApplication.class);
288     ActionServiceContainer actionContainer = uiExplorer.getApplicationComponent(ActionServiceContainer.class);
289     for (ClipboardCommand clipboard : virtualClipboards) {
290       pasteNum++;
291       Node srcNode = null;
292       try{
293         srcNode = (Node)uiExplorer.getSessionByWorkspace(clipboard.getWorkspace()).getItem(clipboard.getSrcPath());
294         String destPath = destNode.getPath();
295         if(destNode.hasNode(srcNode.getName()) ){
296           Node _destNode = destNode.getNode(srcNode.getName());
297           if(_destNode.isNodeType(NodetypeConstant.MIX_VERSIONABLE) && versionedRemember!=null){
298             if(BooleanUtils.isTrue(versionedRemember.get("keepboth"))) {
299               if(ClipboardCommand.COPY.equals(clipboard.getType())) {
300                 pasteByCopy(destNode.getSession(), clipboard.getWorkspace(),
301                         clipboard.getSrcPath(), _destNode.getPath());
302               }else{
303                 pasteByCut(clipboard, uiExplorer, _destNode.getSession(), clipboard.getWorkspace(), clipboard.getSrcPath(),
304                         _destNode.getPath(),actionContainer, false, false, false);
305               }
306             }
307             if(BooleanUtils.isTrue(versionedRemember.get("createVersion")))
308               makeVersion(destNode, _destNode, srcNode, clipboard, action, destPath, uiExplorer, event);
309             processList.remove(clipboard);
310             continue;
311           }
312           if((!_destNode.isNodeType(NodetypeConstant.MIX_VERSIONABLE)) && nonVersionedRemember!=null){
313             if(BooleanUtils.isTrue(nonVersionedRemember.get("replace"))) {
314               //if(ClipboardCommand.CUT.equals(clipboard.getType())) continue;
315               String _destPath = _destNode.getPath();
316               if(!StringUtils.equals(_destPath, clipboard.getSrcPath()) &&
317                       StringUtils.equals(clipboard.getWorkspace(), _destNode.getSession().getWorkspace().getName())) {
318                 TrashService trashService = WCMCoreUtils.getService(TrashService.class);
319                 String trashID = trashService.moveToTrash(_destNode, WCMCoreUtils.getUserSessionProvider());
320 
321                 if(StringUtils.equals(ClipboardCommand.CUT, clipboard.getType())){
322                   pasteByCut(clipboard, uiExplorer, _destNode.getSession(), clipboard.getWorkspace(), clipboard.getSrcPath(),
323                           _destPath, actionContainer, false, false, false);
324                 }else {
325                   UIDocumentAutoVersionForm.copyNode(destNode.getSession(), clipboard.getWorkspace(),
326                           clipboard.getSrcPath(), _destPath, uiApp, uiExplorer, event, ClipboardCommand.COPY);
327                 }
328                 Node deletedNode = trashService.getNodeByTrashId(trashID);
329                 deletedNode.remove();
330                 deletedNode.getSession().save();
331               }
332             }
333             if(BooleanUtils.isTrue(nonVersionedRemember.get("keepboth"))) {
334               if (ClipboardCommand.COPY.equals(clipboard.getType())) {
335                 pasteByCopy(destNode.getSession(), clipboard.getWorkspace(),
336                         clipboard.getSrcPath(), _destNode.getPath());
337               } else {
338                 pasteByCut(clipboard, uiExplorer, _destNode.getSession(), clipboard.getWorkspace(), clipboard.getSrcPath(),
339                         _destNode.getPath(), actionContainer, false, false, false);
340               }
341             }
342             processList.remove(clipboard);
343             continue;
344           }
345           showConfirmDialog(destNode, srcNode, uiExplorer, clipboard, _virtualClipboards, event);
346           break;
347         }else{
348           _virtualClipboards.remove(clipboard);
349           if (pasteNum == virtualClipboards.size()) {
350             processPaste(clipboard, destPath, uiExplorer, event, true, true);
351             processList.remove(clipboard);
352             break;
353           }
354           processPaste(clipboard, destPath, uiExplorer, event, true, false);
355           processList.remove(clipboard);
356         }
357       }catch (ConstraintViolationException ce) {
358         uiApp.addMessage(new ApplicationMessage("UIPopupMenu.msg.current-node-not-allow-paste", null,
359                 ApplicationMessage.WARNING));
360 
361         uiExplorer.updateAjax(event);
362         return;
363       } catch (VersionException ve) {
364         uiApp.addMessage(new ApplicationMessage("UIPopupMenu.msg.copied-node-in-versioning", null,
365                 ApplicationMessage.WARNING));
366 
367         uiExplorer.updateAjax(event);
368         return;
369       } catch (ItemExistsException iee) {
370         uiApp.addMessage(new ApplicationMessage("UIPopupMenu.msg.paste-node-same-name", null,
371                 ApplicationMessage.WARNING));
372 
373         uiExplorer.updateAjax(event);
374         processList.remove(clipboard);
375         continue;
376       } catch (LoginException e) {
377         if (ClipboardCommand.CUT.equals(action)) {
378           uiApp.addMessage(new ApplicationMessage("UIPopupMenu.msg.cannot-login-node", null,
379                   ApplicationMessage.WARNING));
380 
381           uiExplorer.updateAjax(event);
382           return;
383         }
384         uiApp.addMessage(new ApplicationMessage("UIPopupMenu.msg.cannot-paste-nodetype", null,
385                 ApplicationMessage.WARNING));
386 
387         uiExplorer.updateAjax(event);
388         return;
389       } catch (AccessDeniedException ace) {
390         uiApp.addMessage(new ApplicationMessage("UIPopupMenu.msg.access-denied", null,
391                 ApplicationMessage.WARNING));
392 
393         uiExplorer.updateAjax(event);
394         return;
395       } catch (Exception e) {
396         JCRExceptionManager.process(uiApp, e);
397         uiExplorer.updateAjax(event);
398         return;
399       }
400     }
401     if(processList.isEmpty()){
402       UIPopupWindow popupAction = uiExplorer.findFirstComponentOfType(UIPopupWindow.class) ;
403       popupAction.setShow(false) ;
404       uiExplorer.updateAjax(event);
405       versionedRemember.clear();
406       nonVersionedRemember.clear();
407     }
408   }
409 
410   private static void makeVersion(Node destNode, Node _destNode, Node srcNode, ClipboardCommand clipboard,
411                                   String action, String destPath, UIJCRExplorer uiExplorer, Event<?> event) throws Exception{
412     AutoVersionService autoVersionService = WCMCoreUtils.getService(AutoVersionService.class);
413     ActionServiceContainer actionContainer = uiExplorer.getApplicationComponent(ActionServiceContainer.class);
414     UIApplication uiApp = uiExplorer.getAncestorOfType(UIApplication.class);
415     if(destNode.hasNode(srcNode.getName()) && ClipboardCommand.COPY.equals(clipboard.getType())
416             && UIDocumentAutoVersionForm.CREATE_VERSION.equals(action)) {
417       autoVersionService.autoVersion(destNode.getNode(srcNode.getName()), srcNode);
418     }else if(destNode.hasNode(srcNode.getName()) && ClipboardCommand.COPY.equals(clipboard.getType())
419             && UIDocumentAutoVersionForm.KEEP_BOTH.equals(action)){
420       UIDocumentAutoVersionForm.copyNode(destNode.getSession(), destNode.getSession().getWorkspace().getName(),
421               srcNode.getPath(), destNode.getNode(srcNode.getName()).getPath(), uiApp, uiExplorer, event, ClipboardCommand.COPY);
422     }else if(destNode.hasNode(srcNode.getName()) && ClipboardCommand.COPY.equals(clipboard.getType())
423             && UIDocumentAutoVersionForm.REPLACE.equals(action)) {
424       autoVersionService.autoVersion(destNode.getNode(srcNode.getName()), srcNode);
425     } else{
426       if(UIDocumentAutoVersionForm.KEEP_BOTH.equals(action)){
427         if(destNode.hasNode(srcNode.getName())) {
428           pasteByCut(clipboard, uiExplorer, _destNode.getSession(), clipboard.getWorkspace(), clipboard.getSrcPath(),
429                   _destNode.getPath(),actionContainer, false, false, false);
430         }
431       }else {
432         pasteByCut(clipboard, uiExplorer, destNode.getSession(), clipboard.getWorkspace(), clipboard.getSrcPath(),
433                 destNode.getPath(), actionContainer, false, false, true);
434       }
435     }
436     isRefresh=true;
437   }
438 
439   private static void showConfirmDialog(Node destNode, Node srcNode, UIJCRExplorer uiExplorer, ClipboardCommand clipboard,
440                                  Set<ClipboardCommand> virtualClipboards, Event<?> event) throws Exception{
441     Node destExitedNode = destNode.getNode(srcNode.getName());
442     UIPopupContainer objUIPopupContainer = uiExplorer.getChild(UIPopupContainer.class);
443     UIDocumentAutoVersionForm uiDocumentAutoVersionForm = uiExplorer.createUIComponent(UIDocumentAutoVersionForm.class, null, null);
444     uiDocumentAutoVersionForm.setDestPath(destNode.getPath());
445     uiDocumentAutoVersionForm.setDestWorkspace(destNode.getSession().getWorkspace().getName());
446     uiDocumentAutoVersionForm.setSourcePath(srcNode.getPath());
447     uiDocumentAutoVersionForm.setSourceWorkspace(srcNode.getSession().getWorkspace().getName());
448     uiDocumentAutoVersionForm.setCurrentClipboard(clipboard);
449     uiDocumentAutoVersionForm.setMessage("UIDocumentAutoVersionForm.msg");
450     uiDocumentAutoVersionForm.setArguments(new String[]{srcNode.getName()});
451     uiDocumentAutoVersionForm.setClipboardCommands(virtualClipboards);
452     if(virtualClipboards!=null && virtualClipboards.size()==1) uiDocumentAutoVersionForm.setSingleProcess(true);
453     uiDocumentAutoVersionForm.init(destExitedNode);
454     objUIPopupContainer.activate(uiDocumentAutoVersionForm, 450, 0);
455     event.getRequestContext().addUIComponentToUpdateByAjax(objUIPopupContainer);
456     isRefresh = false;
457   }
458   /**
459    * Update clipboard after CUT node. Detain PathNotFoundException with same name sibling node
460    * @param clipboardCommands
461    * @param mapClipboard
462    * @throws Exception
463    */
464   private static void updateClipboard(Set<ClipboardCommand> clipboardCommands,
465                                       Map<ClipboardCommand, Node> mapClipboard) throws Exception {
466     Node srcNode;
467     for (ClipboardCommand clipboard : clipboardCommands) {
468       if (ClipboardCommand.CUT.equals(clipboard.getType())) {
469         srcNode = mapClipboard.get(clipboard);
470         if(srcNode !=null) {
471           srcNode.refresh(true);
472           clipboard.setSrcPath(srcNode.getPath());
473         }
474       }
475     }
476   }
477 
478   /**
479    * Put data from clipboard to Map<Clipboard, Node>. After cutting node, we keep data to update clipboard by respective node
480    * @param clipboardCommands
481    * @param uiExplorer
482    * @return
483    * @throws Exception
484    */
485   private static Map<ClipboardCommand, Node> parseToMap(Set<ClipboardCommand> clipboardCommands,
486                                                         UIJCRExplorer uiExplorer) throws Exception {
487     String srcPath;
488     String type;
489     String srcWorkspace;
490     Node srcNode;
491     Session srcSession;
492     Map<ClipboardCommand, Node> mapClipboard = new HashMap<ClipboardCommand, Node>();
493     for (ClipboardCommand clipboard : clipboardCommands) {
494       srcPath = clipboard.getSrcPath();
495       type = clipboard.getType();
496       srcWorkspace = clipboard.getWorkspace();
497       if (ClipboardCommand.CUT.equals(type)) {
498         srcSession = uiExplorer.getSessionByWorkspace(srcWorkspace);
499         // Use the method getNodeByPath because it is link aware
500         srcNode = uiExplorer.getNodeByPath(srcPath, srcSession, false);
501         clipboard.setSrcPath(srcNode.getPath());
502         mapClipboard.put(clipboard, srcNode);
503       }
504     }
505     return mapClipboard;
506   }
507 
508   private static void processPaste(ClipboardCommand currentClipboard, String destPath, UIJCRExplorer uiExplorer,
509       Event<?> event, boolean isMultiSelect, boolean isLastPaste) throws Exception {
510     UIApplication uiApp = uiExplorer.getAncestorOfType(UIApplication.class);
511     String srcPath = currentClipboard.getSrcPath();
512     String type = currentClipboard.getType();
513     String srcWorkspace = currentClipboard.getWorkspace();
514     Session srcSession = uiExplorer.getSessionByWorkspace(srcWorkspace);
515     // Use the method getNodeByPath because it is link aware
516     Node srcNode = uiExplorer.getNodeByPath(srcPath, srcSession, false);
517     // Reset the path to manage the links that potentially create virtual path
518     srcPath = srcNode.getPath();
519     // Reset the session to manage the links that potentially change of workspace
520     srcSession = srcNode.getSession();
521 
522     // Get thumbnail node of source node
523     ThumbnailService thumbnailService = WCMCoreUtils.getService(ThumbnailService.class);
524     Node srcThumbnailNode = thumbnailService.getThumbnailNode(srcNode);
525 
526     // Reset the workspace name to manage the links that potentially change of
527     // workspace
528     srcWorkspace = srcSession.getWorkspace().getName();
529     Matcher matcher = UIWorkingArea.FILE_EXPLORER_URL_SYNTAX.matcher(destPath);
530     String destWorkspace = null;
531     if (matcher.find()) {
532       destWorkspace = matcher.group(1);
533       destPath = matcher.group(2);
534     }
535     Session destSession = uiExplorer.getSessionByWorkspace(destWorkspace);
536     if(destWorkspace==null) destWorkspace = destSession.getWorkspace().getName();
537     // Use the method getNodeByPath because it is link aware
538     Node destNode = uiExplorer.getNodeByPath(destPath, destSession);
539 
540     // Reset the path to manage the links that potentially create virtual path
541     destPath = destNode.getPath();
542     // Reset the session to manage the links that potentially change of
543     // workspace
544     destSession = destNode.getSession();
545     if (ClipboardCommand.CUT.equals(type) && srcPath.equals(destPath)) {
546       uiApp.addMessage(new ApplicationMessage("UIPopupMenu.msg.node-cutting", null,
547           ApplicationMessage.WARNING));
548 
549       return;
550     }
551     // Make destination path without index on final name
552     if (!"/".equals(destPath))
553       destPath = destPath.concat("/");
554     destPath = destPath.concat(srcNode.getName());
555     ActionServiceContainer actionContainer = uiExplorer
556         .getApplicationComponent(ActionServiceContainer.class);
557     try {
558       if (ClipboardCommand.COPY.equals(type)) {
559 
560         pasteByCopy(destSession, srcWorkspace, srcPath, destPath);
561         destNode = (Node) destSession.getItem(destPath);
562         actionContainer.initiateObservation(destNode);
563       } else {
564         pasteByCut(currentClipboard, uiExplorer, destSession, srcWorkspace, srcPath, destPath,
565             actionContainer, isMultiSelect, isLastPaste, false);
566         destNode = (Node) destSession.getItem(destPath);
567       }
568 
569       if (!srcWorkspace.equals(destWorkspace) || !srcPath.equals(destPath)) {
570         // Update thumbnail for the node after pasting
571         thumbnailService.copyThumbnailNode(srcThumbnailNode, destNode);
572       }
573     } catch (ConstraintViolationException ce) {
574       uiApp.addMessage(new ApplicationMessage("UIPopupMenu.msg.current-node-not-allow-paste", null,
575           ApplicationMessage.WARNING));
576 
577       uiExplorer.updateAjax(event);
578       return;
579     } catch (VersionException ve) {
580       uiApp.addMessage(new ApplicationMessage("UIPopupMenu.msg.copied-node-in-versioning", null,
581           ApplicationMessage.WARNING));
582 
583       uiExplorer.updateAjax(event);
584       return;
585     } catch (ItemExistsException iee) {
586       uiApp.addMessage(new ApplicationMessage("UIPopupMenu.msg.paste-node-same-name", null,
587           ApplicationMessage.WARNING));
588 
589       uiExplorer.updateAjax(event);
590       return;
591     } catch (LoginException e) {
592       if (ClipboardCommand.CUT.equals(type)) {
593         uiApp.addMessage(new ApplicationMessage("UIPopupMenu.msg.cannot-login-node", null,
594             ApplicationMessage.WARNING));
595 
596         uiExplorer.updateAjax(event);
597         return;
598       }
599       uiApp.addMessage(new ApplicationMessage("UIPopupMenu.msg.cannot-paste-nodetype", null,
600           ApplicationMessage.WARNING));
601 
602       uiExplorer.updateAjax(event);
603       return;
604     } catch (AccessDeniedException ace) {
605       uiApp.addMessage(new ApplicationMessage("UIPopupMenu.msg.access-denied", null,
606           ApplicationMessage.WARNING));
607 
608       uiExplorer.updateAjax(event);
609       return;
610     } catch (LockException locke) {
611       Object[] arg = { srcPath };
612       uiApp.addMessage(new ApplicationMessage("UIPopupMenu.msg.paste-lock-exception", arg,
613           ApplicationMessage.WARNING));
614 
615     } catch (Exception e) {
616       JCRExceptionManager.process(uiApp, e);
617 
618       uiExplorer.updateAjax(event);
619       return;
620     }
621   }
622 
623   private static void removeReferences(Node destNode) throws Exception {
624     NodeType[] mixinTypes = destNode.getMixinNodeTypes();
625     Session session = destNode.getSession();
626     for (int i = 0; i < mixinTypes.length; i++) {
627       if (mixinTypes[i].getName().equals(Utils.EXO_CATEGORIZED)
628           && destNode.hasProperty(Utils.EXO_CATEGORIZED)) {
629         Node valueNode = null;
630         Value valueAdd = session.getValueFactory().createValue(valueNode);
631         destNode.setProperty(Utils.EXO_CATEGORIZED, new Value[] { valueAdd });
632       }
633     }
634     destNode.save();
635   }
636 
637   private static void pasteByCopy(Session session, String srcWorkspaceName, String srcPath,
638       String destPath) throws Exception {
639     Workspace workspace = session.getWorkspace();
640     if (workspace.getName().equals(srcWorkspaceName)) {
641       workspace.copy(srcPath, destPath);
642       Node destNode = (Node) session.getItem(destPath);
643       removeReferences(destNode);
644     } else {
645       try {
646         if (LOG.isDebugEnabled())
647           LOG.debug("Copy to another workspace");
648         workspace.copy(srcWorkspaceName, srcPath, destPath);
649       } catch (Exception e) {
650         if (LOG.isErrorEnabled()) {
651           LOG.error("an unexpected error occurs while pasting the node", e);
652         }
653         if (LOG.isDebugEnabled())
654           LOG.debug("Copy to other workspace by clone");
655         try {
656           workspace.clone(srcWorkspaceName, srcPath, destPath, false);
657         } catch (Exception f) {
658           if (LOG.isErrorEnabled()) {
659             LOG.error("an unexpected error occurs while pasting the node", f);
660           }
661         }
662       }
663     }
664   }
665 
666   public static void pasteByCut(ClipboardCommand currentClipboard, UIJCRExplorer uiExplorer,
667       Session session, String srcWorkspace, String srcPath, String destPath,
668       ActionServiceContainer actionContainer, boolean isMultiSelect,
669       boolean isLastPaste, boolean isCreateVersion) throws Exception {
670     ClipboardService clipboardService = WCMCoreUtils.getService(ClipboardService.class);
671     String userId = ConversationState.getCurrent().getIdentity().getUserId();
672 
673     UIWorkingArea uiWorkingArea = uiExplorer.getChild(UIWorkingArea.class);
674     Workspace workspace = session.getWorkspace();
675     if (workspace.getName().equals(srcWorkspace)) {
676       if (srcPath.equals(destPath))
677         return;
678     }
679     Set<ClipboardCommand> allClipboard = clipboardService.getClipboardList(userId, false);
680     Set<ClipboardCommand> virtualClipboard = clipboardService.getClipboardList(userId, true);
681     Map<ClipboardCommand, Node> mapAllClipboardNode = parseToMap(allClipboard, uiExplorer);
682     Map<ClipboardCommand, Node> mapVirtualClipboardNode = parseToMap(virtualClipboard, uiExplorer);
683 
684     RelationsService relationsService = uiExplorer.getApplicationComponent(RelationsService.class);
685     List<Node> refList = new ArrayList<Node>();
686     boolean isReference = false;
687     PropertyIterator references = null;
688     Node srcNode = (Node) uiExplorer.getSessionByWorkspace(srcWorkspace).getItem(srcPath);
689     try {
690       references = srcNode.getReferences();
691       isReference = true;
692     } catch (Exception e) {
693       isReference = false;
694     }
695     if (isReference && references != null) {
696       if (references.getSize() > 0) {
697         while (references.hasNext()) {
698           Property pro = references.nextProperty();
699           Node refNode = pro.getParent();
700           if (refNode.hasProperty(RELATION_PROP)) {
701             relationsService.removeRelation(refNode, srcPath);
702             refNode.save();
703             refList.add(refNode);
704           }
705         }
706       }
707     }
708     // Add locked token for the source node
709     ListenerService listenerService = WCMCoreUtils.getService(ListenerService.class);
710     ActivityCommonService activityService = WCMCoreUtils.getService(ActivityCommonService.class);
711     uiExplorer.addLockToken(srcNode);
712     if (workspace.getName().equals(srcWorkspace)) {
713       try {
714         if(isCreateVersion){
715           Node _destNode = ((Node)session.getItem(destPath)).getNode(srcNode.getName());
716           AutoVersionService autoVersionService = WCMCoreUtils.getService(AutoVersionService.class);
717           autoVersionService.autoVersion(_destNode, srcNode);
718           if(!srcNode.getPath().equals(_destNode.getPath())) {
719             srcNode.remove();
720           }
721         }else {
722           workspace.move(srcPath, destPath);
723         }
724         LockUtil.changeLockToken(srcPath, (Node)session.getItem(destPath));
725       } catch (ArrayIndexOutOfBoundsException e) {
726         throw new MessageException(new ApplicationMessage("UIPopupMenu.msg.node-cutting", null,
727             ApplicationMessage.WARNING));
728       }
729       if (!isMultiSelect || (isMultiSelect && isLastPaste)) {
730         Node desNode = null;
731         try {
732           desNode = (Node) session.getItem(destPath);
733         } catch (PathNotFoundException pathNotFoundException) {
734           uiExplorer.setCurrentPath(LinkUtils.getParentPath(uiExplorer.getCurrentPath()));
735           desNode = uiExplorer.getCurrentNode();
736         } catch (ItemNotFoundException itemNotFoundException) {
737           uiExplorer.setCurrentPath(LinkUtils.getParentPath(uiExplorer.getCurrentPath()));
738           desNode = uiExplorer.getCurrentNode();
739         }
740 
741         if (!session.itemExists(uiExplorer.getCurrentPath())) {
742           uiExplorer.setCurrentPath(LinkUtils.getParentPath(uiExplorer.getCurrentPath()));
743         }
744         if (activityService.isAcceptedNode(desNode) || desNode.getPrimaryNodeType().getName().equals(NodetypeConstant.NT_FILE)) {
745           listenerService.broadcast(ActivityCommonService.NODE_MOVED_ACTIVITY, desNode, desNode.getPath());
746         }
747         if (!(desNode.getPath().equals(uiExplorer.getCurrentPath())))
748           actionContainer.initiateObservation(desNode);
749         for (int i = 0; i < refList.size(); i++) {
750           Node addRef = refList.get(i);
751           relationsService.addRelation(addRef, destPath, session.getWorkspace().getName());
752           addRef.save();
753         }
754         clipboardService.clearClipboardList(userId, true);
755         Node currentNode = uiExplorer.getCurrentNode();
756         String realCurrentPath = currentNode.getPath();
757         if (srcWorkspace.equals(currentNode.getSession().getWorkspace().getName())
758             && (srcPath.equals(realCurrentPath) || realCurrentPath.startsWith(srcPath))) {
759           uiExplorer.setCurrentPath(LinkUtils.getParentPath(uiExplorer.getCurrentPath()));
760         }
761       }
762     } else {
763       workspace.clone(srcWorkspace, srcPath, destPath, false);
764       Node desNode =(Node) workspace.getSession().getItem(destPath);
765       if (activityService.isAcceptedNode(desNode) || desNode.getPrimaryNodeType().getName().equals(NodetypeConstant.NT_FILE)) {
766         listenerService.broadcast(ActivityCommonService.NODE_MOVED_ACTIVITY, desNode, destPath);
767       }
768       if (!isMultiSelect || (isMultiSelect && isLastPaste)) {
769         clipboardService.clearClipboardList(userId, true);
770       }
771     }
772     clipboardService.getClipboardList(userId, false).remove(currentClipboard);
773     updateClipboard(clipboardService.getClipboardList(userId, true), mapVirtualClipboardNode);
774     updateClipboard(clipboardService.getClipboardList(userId, false), mapAllClipboardNode);
775     clipboardService.clearClipboardList(userId, true);
776     clipboardService.clearClipboardList(userId, false);
777   }
778 
779   public static class PasteActionListener extends UIWorkingAreaActionListener<PasteManageComponent> {
780     public void processEvent(Event<PasteManageComponent> event) throws Exception {
781       UIJCRExplorer uiExplorer = event.getSource().getAncestorOfType(UIJCRExplorer.class);
782       pasteManage(event, uiExplorer);
783     }
784   }
785 
786   @Override
787   public Class<? extends UIAbstractManager> getUIAbstractManagerClass() {
788     return null;
789   }
790 
791   public static void setVersionedRemember(Map<String, Boolean> versionedRemember) {
792     PasteManageComponent.versionedRemember.clear();
793     if(versionedRemember != null && !versionedRemember.isEmpty()) {
794       PasteManageComponent.versionedRemember.putAll(versionedRemember);
795     }
796   }
797 
798   public static void setNonVersionedRemember(Map<String, Boolean> nonVersionedRemember) {
799     PasteManageComponent.nonVersionedRemember.clear();
800     if(nonVersionedRemember != null && !nonVersionedRemember.isEmpty()) {
801       PasteManageComponent.nonVersionedRemember.putAll(nonVersionedRemember);
802     }
803   }
804 
805   public static Map<String, Boolean> getVersionedRemember() {
806     return versionedRemember;
807   }
808 }