1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.exoplatform.ecm.webui.component.explorer.versions;
18
19 import java.io.Serializable;
20 import java.util.ArrayList;
21 import java.util.Comparator;
22 import java.util.List;
23
24 import javax.jcr.Node;
25 import javax.jcr.ReferentialIntegrityException;
26 import javax.jcr.RepositoryException;
27 import javax.jcr.version.Version;
28 import javax.jcr.version.VersionException;
29 import javax.jcr.version.VersionHistory;
30
31 import org.apache.commons.lang.StringUtils;
32
33 import org.exoplatform.commons.utils.LazyPageList;
34 import org.exoplatform.commons.utils.ListAccess;
35 import org.exoplatform.commons.utils.ListAccessImpl;
36 import org.exoplatform.ecm.jcr.model.VersionNode;
37 import org.exoplatform.ecm.webui.component.explorer.UIDocumentWorkspace;
38 import org.exoplatform.ecm.webui.component.explorer.UIJCRExplorer;
39 import org.exoplatform.ecm.webui.utils.Utils;
40 import org.exoplatform.services.cache.CacheService;
41 import org.exoplatform.services.cache.ExoCache;
42 import org.exoplatform.services.cms.documents.AutoVersionService;
43 import org.exoplatform.services.cms.documents.DocumentService;
44 import org.exoplatform.services.cms.documents.VersionHistoryUtils;
45 import org.exoplatform.services.cms.jcrext.activity.ActivityCommonService;
46 import org.exoplatform.services.jcr.core.ManageableRepository;
47 import org.exoplatform.services.jcr.impl.storage.JCRInvalidItemStateException;
48 import org.exoplatform.services.listener.ListenerService;
49 import org.exoplatform.services.log.ExoLogger;
50 import org.exoplatform.services.log.Log;
51 import org.exoplatform.services.pdfviewer.ObjectKey;
52 import org.exoplatform.services.pdfviewer.PDFViewerService;
53 import org.exoplatform.services.security.ConversationState;
54 import org.exoplatform.services.security.MembershipEntry;
55 import org.exoplatform.services.wcm.core.NodeLocation;
56 import org.exoplatform.services.wcm.utils.WCMCoreUtils;
57 import org.exoplatform.wcm.connector.viewer.PDFViewerRESTService;
58 import org.exoplatform.web.application.ApplicationMessage;
59 import org.exoplatform.webui.config.annotation.ComponentConfig;
60 import org.exoplatform.webui.config.annotation.EventConfig;
61 import org.exoplatform.webui.core.UIApplication;
62 import org.exoplatform.webui.core.UIComponent;
63 import org.exoplatform.webui.core.UIContainer;
64 import org.exoplatform.webui.core.UIPageIterator;
65 import org.exoplatform.webui.event.Event;
66 import org.exoplatform.webui.event.EventListener;
67
68
69
70
71
72
73
74
75
76 @ComponentConfig(
77 template = "app:/groovy/webui/component/explorer/versions/UIVersionInfo.gtmpl",
78 events = {
79 @EventConfig(listeners = UIVersionInfo.SelectActionListener.class),
80 @EventConfig(listeners = UIVersionInfo.RestoreVersionActionListener.class, confirm = "UIVersionInfo.msg.confirm-restore"),
81 @EventConfig(listeners = UIVersionInfo.CompareVersionActionListener.class, csrfCheck = false),
82 @EventConfig(listeners = UIVersionInfo.DeleteVersionActionListener.class, confirm = "UIVersionInfo.msg.confirm-delete"),
83 @EventConfig(listeners = UIVersionInfo.CloseActionListener.class),
84 @EventConfig(listeners = UIVersionInfo.AddSummaryActionListener.class)
85 }
86 )
87
88 public class UIVersionInfo extends UIContainer {
89 private static final Log LOG = ExoLogger.getLogger(UIVersionInfo.class.getName());
90
91 protected VersionNode rootVersion_ ;
92 protected String rootOwner_;
93 protected String rootVersionNum_;
94 protected VersionNode curentVersion_;
95 protected NodeLocation node_ ;
96 private UIPageIterator uiPageIterator_ ;
97 private List<VersionNode> listVersion = new ArrayList<VersionNode>() ;
98
99 private static final String CACHE_NAME = "ecms.PDFViewerRestService";
100
101
102 public UIVersionInfo() throws Exception {
103 uiPageIterator_ = addChild(UIPageIterator.class, null, "VersionInfoIterator").setRendered(false);
104 }
105
106 public UIPageIterator getUIPageIterator() { return uiPageIterator_; }
107
108 @SuppressWarnings("rawtypes")
109 public List getListRecords() throws Exception { return uiPageIterator_.getCurrentPageData(); }
110
111 public void updateGrid() throws Exception {
112 listVersion.clear();
113 Node currentNode = getCurrentNode();
114 rootVersion_ = new VersionNode(currentNode, currentNode.getSession());
115 curentVersion_ = rootVersion_;
116
117 listVersion = getNodeVersions(getRootVersionNode().getChildren());
118 VersionNode currentNodeTuple = new VersionNode(currentNode, currentNode.getSession());
119 if(!listVersion.isEmpty()) {
120 int lastVersionNum = Integer.parseInt(listVersion.get(0).getName());
121 setRootVersionNum(String.valueOf(++lastVersionNum));
122 } else {
123 setRootVersionNum("1");
124 }
125 listVersion.add(0, currentNodeTuple);
126
127 ListAccess<VersionNode> recordList = new ListAccessImpl<VersionNode>(VersionNode.class, listVersion);
128 LazyPageList<VersionNode> dataPageList = new LazyPageList<VersionNode>(recordList, 10);
129 uiPageIterator_.setPageList(dataPageList);
130 }
131
132 public String getTitle(Node node) throws Exception {
133 return org.exoplatform.ecm.webui.utils.Utils.getTitle(node);
134 }
135
136 private boolean isRestoredVersions(List<VersionNode> list) {
137 try {
138 for (int i = 0; i < list.size(); i++) {
139 if (getVersionLabels(list.get(i)).length > 0) {
140 if (isRestoredLabel(getVersionLabels(list.get(i))[0])) return true;
141 }
142 }
143 } catch (Exception e) {
144 return false;
145 }
146 return false;
147 }
148
149 private boolean isRestoredLabel(String label) {
150 try {
151 String from = label.substring(label.indexOf("_") - 1).split("_")[0];
152 String to = label.substring(label.indexOf("_") - 1).split("_")[1];
153 Integer.parseInt(from);
154 Integer.parseInt(to);
155 return true;
156 } catch (Exception e) {
157 return false;
158 }
159 }
160
161 public String[] getVersionLabels(VersionNode version) throws Exception {
162 VersionHistory vH = NodeLocation.getNodeByLocation(node_).getVersionHistory();
163 String[] labels;
164 if (StringUtils.isNotBlank(version.getName()) && !getRootVersionNum().equals(version.getName())) {
165 Version versionNode = vH.getVersion(version.getName());
166 labels = vH.getVersionLabels(versionNode);
167 } else {
168 labels= vH.getVersionLabels(vH.getRootVersion());
169 }
170 return labels;
171 }
172
173 public boolean isBaseVersion(VersionNode versionNode) throws Exception {
174 if (!isRestoredVersions(listVersion)) {
175 return isRootVersion(versionNode);
176 } else {
177 return versionNode.getPath().equals(getCurrentNode().getPath());
178 }
179 }
180
181 public boolean hasPermission(Node node) throws Exception {
182 if (getCurrentNode().getPath().startsWith("/Groups/spaces")) {
183 MembershipEntry mem = new MembershipEntry("/spaces/" + getCurrentNode().getPath().split("/")[3], "manager");
184 return (ConversationState.getCurrent().getIdentity().getMemberships().contains(mem)
185 || ConversationState.getCurrent().getIdentity().getUserId().equals(node.getProperty("exo:lastModifier").getString()));
186
187 } else {
188 return true;
189 }
190 }
191
192 public boolean isRootVersion(VersionNode versionNode) throws Exception {
193 return (versionNode.getUUID().equals(getCurrentNode().getUUID()));
194 }
195
196 public VersionNode getRootVersionNode() throws Exception { return rootVersion_ ; }
197
198 public String getRootOwner() throws Exception { return rootOwner_ ; }
199
200 public void setRootOwner(String user) { this.rootOwner_ = user; }
201
202 private List<VersionNode> getNodeVersions(List<VersionNode> children) throws Exception {
203 List<VersionNode> child = new ArrayList<VersionNode>() ;
204 for(int i = 0; i < children.size(); i ++){
205 listVersion.add(children.get(i));
206 child = children.get(i).getChildren() ;
207 if(!child.isEmpty()) getNodeVersions(child) ;
208 }
209 listVersion.sort(new Comparator<VersionNode>() {
210 @Override
211 public int compare(VersionNode v1, VersionNode v2) {
212 try {
213 if (Integer.parseInt(v1.getName()) < Integer.parseInt(v2.getName()))
214 return 1;
215 else
216 return 0;
217 }catch (Exception e) {
218 return 0;
219 }
220 }
221 });
222 return listVersion;
223 }
224
225 public void activate() {
226 try {
227 UIJCRExplorer uiExplorer = getAncestorOfType(UIJCRExplorer.class);
228 if (node_ == null) {
229 node_ = NodeLocation.getNodeLocationByNode(uiExplorer.getCurrentNode());
230 }
231 updateGrid();
232 } catch (Exception e) {
233 LOG.error("Unexpected error!", e);
234 }
235 }
236
237 public VersionNode getCurrentVersionNode() { return curentVersion_ ;}
238
239 public Node getVersion(String versionName) throws RepositoryException {
240 Node currentNode = getCurrentNode();
241 if ((StringUtils.isBlank(versionName) && StringUtils.isBlank(getCurrentVersionNode().getName()))
242 || (StringUtils.isNotBlank(versionName) && StringUtils.isNotBlank(getCurrentVersionNode().getName())
243 && getCurrentVersionNode().getName().equals(versionName))) {
244 return currentNode;
245 }
246 for (VersionNode versionNode : listVersion) {
247 if(versionNode.getName().equals(versionName)) {
248 return currentNode.getVersionHistory().getVersion(versionName);
249 }
250 }
251 return null;
252 }
253
254 public Node getCurrentNode() {
255 return NodeLocation.getNodeByLocation(node_);
256 }
257
258 public void setCurrentNode(Node node) {
259 node_ = NodeLocation.getNodeLocationByNode(node);
260 }
261
262 public List<VersionNode> getListVersion() {
263 return listVersion;
264 }
265
266 public void setListVersion(List<VersionNode> listVersion) {
267 this.listVersion = listVersion;
268 }
269
270 public String getLinkInDocumentsApp(String nodePath) throws Exception {
271 DocumentService documentService = WCMCoreUtils.getService(DocumentService.class);
272 return documentService.getLinkInDocumentsApp(nodePath);
273 }
274
275 public void setRootVersionNum(String rootVersionNum) {
276 this.rootVersionNum_ = rootVersionNum;
277 }
278
279 public String getRootVersionNum() {
280 return rootVersionNum_;
281 }
282
283 private boolean isWebContent() throws Exception {
284 Node currentNode = getCurrentNode();
285 if (currentNode != null) {
286 return currentNode.isNodeType(Utils.EXO_WEBCONTENT);
287 }
288 return false;
289 }
290
291 static public class RestoreVersionActionListener extends EventListener<UIVersionInfo> {
292 public void execute(Event<UIVersionInfo> event) throws Exception {
293 UIVersionInfo uiVersionInfo = event.getSource();
294 UIJCRExplorer uiExplorer = uiVersionInfo.getAncestorOfType(UIJCRExplorer.class) ;
295 PDFViewerService pdfViewerService = WCMCoreUtils.getService(PDFViewerService.class);
296 CacheService caService = WCMCoreUtils.getService(CacheService.class);
297 ExoCache<Serializable, Object> pdfCache;
298 if(pdfViewerService != null){
299 pdfCache = pdfViewerService.getCache();
300 }else{
301 pdfCache = caService.getCacheInstance(CACHE_NAME);
302 }
303 for(UIComponent uiChild : uiVersionInfo.getChildren()) {
304 uiChild.setRendered(false) ;
305 }
306 String objectId = event.getRequestContext().getRequestParameter(OBJECTID) ;
307 VersionNode currentVersionNode = uiVersionInfo.rootVersion_.findVersionNode(objectId);
308 String fromVersionName = currentVersionNode.getName() ;
309 UIApplication uiApp = uiVersionInfo.getAncestorOfType(UIApplication.class) ;
310 Node currentNode = uiVersionInfo.getCurrentNode();
311 uiExplorer.addLockToken(currentNode);
312 try {
313 if(!currentNode.isCheckedOut()) {
314 currentNode.checkout();
315 }
316 AutoVersionService autoVersionService = WCMCoreUtils.getService(AutoVersionService.class);
317 Version addedVersion = autoVersionService.autoVersion(currentNode);
318 currentNode.restore(fromVersionName,true);
319 if(!currentNode.isCheckedOut()) {
320 currentNode.checkout();
321 }
322 StringBuilder bd = new StringBuilder();
323 bd.append(((ManageableRepository)currentNode.getSession().getRepository()).getConfiguration().getName()).
324 append("/").append(currentNode.getSession().getWorkspace().getName()).append("/").
325 append(currentNode.getUUID());
326 StringBuilder bd1 = new StringBuilder().append(bd).append("/jcr:lastModified");
327 StringBuilder bd2 = new StringBuilder().append(bd).append("/jcr:baseVersion");
328 pdfCache.remove(new ObjectKey(bd.toString()));
329 pdfCache.remove(new ObjectKey(bd1.toString()));
330 pdfCache.remove(new ObjectKey(bd2.toString()));
331
332 int lastVersionIndice = Integer.parseInt(addedVersion.getName());
333
334 String restoredFromMsg = "UIDiff.label.restoredFrom_" + fromVersionName + "_" + (lastVersionIndice + 1);
335 VersionHistory versionHistory = currentNode.getVersionHistory();
336 versionHistory.addVersionLabel(versionHistory.getRootVersion().getName(), restoredFromMsg, false);
337
338 ListenerService listenerService = WCMCoreUtils.getService(ListenerService.class);
339 ActivityCommonService activityService = WCMCoreUtils.getService(ActivityCommonService.class);
340 try {
341 if (listenerService!=null && activityService !=null && activityService.isAcceptedNode(currentNode)) {
342 listenerService.broadcast(ActivityCommonService.NODE_REVISION_CHANGED, currentNode, fromVersionName);
343 }
344 }catch (Exception e) {
345 if (LOG.isErrorEnabled()) {
346 LOG.error("Can not notify NodeMovedActivity: " + e.getMessage());
347 }
348 }
349 } catch(JCRInvalidItemStateException invalid) {
350 uiApp.addMessage(new ApplicationMessage("UIVersionInfo.msg.invalid-item-state", null,
351 ApplicationMessage.WARNING)) ;
352
353 return ;
354 } catch(NullPointerException nuException){
355 uiApp.addMessage(new ApplicationMessage("UIVersionInfo.msg.invalid-item-state", null,
356 ApplicationMessage.WARNING)) ;
357
358 return;
359 } catch(Exception e) {
360
361 uiApp.addMessage(new ApplicationMessage("UIVersionInfo.msg.invalid-item-state", null,
362 ApplicationMessage.WARNING)) ;
363
364 return;
365 }
366 uiVersionInfo.activate();
367 event.getRequestContext().addUIComponentToUpdateByAjax(uiVersionInfo) ;
368 uiExplorer.setIsHidePopup(true) ;
369 }
370 }
371
372 static public class DeleteVersionActionListener extends EventListener<UIVersionInfo> {
373 public void execute(Event<UIVersionInfo> event) throws Exception {
374 UIVersionInfo uiVersionInfo = event.getSource();
375 UIJCRExplorer uiExplorer = uiVersionInfo.getAncestorOfType(UIJCRExplorer.class);
376 for (UIComponent uiChild : uiVersionInfo.getChildren()) {
377 uiChild.setRendered(false);
378 }
379 String objectId = event.getRequestContext().getRequestParameter(OBJECTID);
380 uiVersionInfo.curentVersion_ = uiVersionInfo.getRootVersionNode().findVersionNode(objectId);
381 Node node = uiVersionInfo.getCurrentNode();
382 UIApplication app = uiVersionInfo.getAncestorOfType(UIApplication.class);
383 try {
384 node.getSession().save();
385 node.getSession().refresh(false);
386 VersionHistoryUtils.removeVersion(uiVersionInfo.getCurrentNode(), uiVersionInfo.curentVersion_.getName() );
387 uiVersionInfo.rootVersion_ = new VersionNode(node, uiExplorer.getSession());
388 uiVersionInfo.curentVersion_ = uiVersionInfo.rootVersion_;
389 if (!node.isCheckedOut())
390 node.checkout();
391 uiExplorer.getSession().save();
392 uiVersionInfo.activate();
393 event.getRequestContext().addUIComponentToUpdateByAjax(uiVersionInfo);
394 } catch (ReferentialIntegrityException rie) {
395 if (LOG.isErrorEnabled()) {
396 LOG.error("Unexpected error", rie);
397 }
398 app.addMessage(new ApplicationMessage("UIVersionInfo.msg.error-removing-referenced-version", null, ApplicationMessage.ERROR));
399 return;
400 } catch (Exception e) {
401 if (LOG.isErrorEnabled()) {
402 LOG.error("Unexpected error", e);
403 }
404 app.addMessage(new ApplicationMessage("UIVersionInfo.msg.error-removing-version", null, ApplicationMessage.ERROR));
405 return;
406 }
407 }
408 }
409
410 static public class CompareVersionActionListener extends EventListener<UIVersionInfo> {
411 public void execute(Event<UIVersionInfo> event) throws Exception {
412 UIVersionInfo uiVersionInfo = event.getSource();
413 UIDocumentWorkspace uiDocumentWorkspace = uiVersionInfo.getAncestorOfType(UIDocumentWorkspace.class);
414 for (UIComponent uiChild : uiDocumentWorkspace.getChildren()) {
415 uiChild.setRendered(false);
416 }
417 String fromVersionName = event.getRequestContext().getRequestParameter("versions").split(",")[0];
418 String toVersionName = event.getRequestContext().getRequestParameter("versions").split(",")[1];
419 UIDiff uiDiff = uiDocumentWorkspace.getChild(UIDiff.class);
420 uiDiff.setVersions(uiVersionInfo.getVersion(fromVersionName), uiVersionInfo.getVersion(toVersionName));
421 uiDiff.setRendered(true);
422 event.getRequestContext().addUIComponentToUpdateByAjax(uiDocumentWorkspace);
423 }
424 }
425
426 static public class SelectActionListener extends EventListener<UIVersionInfo> {
427 public void execute(Event<UIVersionInfo> event) throws Exception {
428 UIVersionInfo uiVersionInfo = event.getSource() ;
429 String path = event.getRequestContext().getRequestParameter(OBJECTID) ;
430 VersionNode root = uiVersionInfo.getRootVersionNode() ;
431 VersionNode selectedVersion= root.findVersionNode(path);
432 selectedVersion.setExpanded(!selectedVersion.isExpanded()) ;
433 event.getRequestContext().addUIComponentToUpdateByAjax(uiVersionInfo) ;
434 }
435 }
436
437 static public class CloseActionListener extends EventListener<UIVersionInfo> {
438 public void execute(Event<UIVersionInfo> event) throws Exception {
439 UIVersionInfo uiVersionInfo = event.getSource();
440 for(UIComponent uiChild : uiVersionInfo.getChildren()) {
441 if (uiChild.isRendered()) {
442 uiChild.setRendered(false);
443 return ;
444 }
445 }
446 UIJCRExplorer uiExplorer = uiVersionInfo.getAncestorOfType(UIJCRExplorer.class) ;
447 uiExplorer.updateAjax(event) ;
448 }
449 }
450
451 public static class AddSummaryActionListener extends EventListener<UIVersionInfo> {
452 public void execute(Event<UIVersionInfo> event) throws Exception {
453 UIVersionInfo uiVersionInfo = event.getSource();
454 String objectId = event.getRequestContext().getRequestParameter(OBJECTID) ;
455 uiVersionInfo.curentVersion_ = uiVersionInfo.rootVersion_.findVersionNode(objectId) ;
456 String currentVersionName = uiVersionInfo.curentVersion_.getName();
457 if(StringUtils.isBlank(currentVersionName)) {
458 currentVersionName = uiVersionInfo.getRootVersionNum();
459 }
460 String summary = event.getRequestContext().getRequestParameter("value") + "_" + currentVersionName;
461 UIJCRExplorer uiExplorer = uiVersionInfo.getAncestorOfType(UIJCRExplorer.class) ;
462 UIApplication uiApp = uiVersionInfo.getAncestorOfType(UIApplication.class) ;
463 Node currentNode = uiExplorer.getCurrentNode() ;
464 if(!Utils.isNameValid(summary, Utils.SPECIALCHARACTER)) {
465 uiApp.addMessage(new ApplicationMessage("UILabelForm.msg.label-invalid",
466 null, ApplicationMessage.WARNING)) ;
467 return ;
468 }
469 try{
470 if(StringUtils.isNotBlank(summary) && !currentNode.getVersionHistory().hasVersionLabel(summary)) {
471 Version currentVersion = null;
472 if(currentVersionName.equals(uiVersionInfo.getRootVersionNum())) {
473 currentVersion = currentNode.getVersionHistory().getRootVersion();
474 } else {
475 currentVersion = currentNode.getVersionHistory().getVersion(currentVersionName);
476 }
477 String[] versionLabels = currentNode.getVersionHistory().getVersionLabels(currentVersion);
478 for(String label : versionLabels) {
479 currentNode.getVersionHistory().removeVersionLabel(label);
480 }
481 currentNode.getVersionHistory().addVersionLabel(currentVersion.getName(), summary, false);
482 }
483 } catch (VersionException ve) {
484 uiApp.addMessage(new ApplicationMessage("UILabelForm.msg.label-exist", new Object[]{summary})) ;
485 return ;
486 }
487 event.getRequestContext().addUIComponentToUpdateByAjax(uiVersionInfo) ;
488 }
489 }
490 }