001/* 002 * (C) Copyright 2006-2012 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Razvan Caraghin 016 * Florent Guillaume 017 * Thierry Martins 018 * Antoine Taillefer 019 */ 020 021package org.nuxeo.ecm.webapp.versioning; 022 023import static org.jboss.seam.ScopeType.CONVERSATION; 024import static org.jboss.seam.ScopeType.EVENT; 025import static org.jboss.seam.annotations.Install.FRAMEWORK; 026import static org.nuxeo.ecm.webapp.helpers.EventNames.DOCUMENT_CHANGED; 027import static org.nuxeo.ecm.webapp.helpers.EventNames.DOCUMENT_PUBLISHED; 028import static org.nuxeo.ecm.webapp.helpers.EventNames.DOCUMENT_SELECTION_CHANGED; 029import static org.nuxeo.ecm.webapp.helpers.EventNames.DOCUMENT_SUBMITED_FOR_PUBLICATION; 030 031import java.io.Serializable; 032import java.util.ArrayList; 033import java.util.List; 034 035import org.apache.commons.logging.Log; 036import org.apache.commons.logging.LogFactory; 037import org.jboss.seam.annotations.Create; 038import org.jboss.seam.annotations.Factory; 039import org.jboss.seam.annotations.In; 040import org.jboss.seam.annotations.Install; 041import org.jboss.seam.annotations.Name; 042import org.jboss.seam.annotations.Observer; 043import org.jboss.seam.annotations.Scope; 044import org.jboss.seam.annotations.intercept.BypassInterceptors; 045import org.jboss.seam.contexts.Context; 046import org.jboss.seam.faces.FacesMessages; 047import org.jboss.seam.international.StatusMessage; 048import org.nuxeo.ecm.core.api.CoreSession; 049import org.nuxeo.ecm.core.api.DocumentModel; 050import org.nuxeo.ecm.core.api.DocumentRef; 051import org.nuxeo.ecm.core.api.IdRef; 052import org.nuxeo.ecm.core.api.VersionModel; 053import org.nuxeo.ecm.core.api.impl.VersionModelImpl; 054import org.nuxeo.ecm.core.api.security.SecurityConstants; 055import org.nuxeo.ecm.platform.query.api.PageSelection; 056import org.nuxeo.ecm.platform.query.api.PageSelections; 057import org.nuxeo.ecm.platform.ui.web.api.NavigationContext; 058import org.nuxeo.ecm.platform.ui.web.api.UserAction; 059import org.nuxeo.ecm.webapp.documentsLists.DocumentsListsManager; 060import org.nuxeo.ecm.webapp.helpers.EventManager; 061import org.nuxeo.ecm.webapp.helpers.ResourcesAccessor; 062 063/** 064 * Deals with versioning actions. 065 * 066 * @author Razvan Caraghin 067 * @author Florent Guillaume 068 * @author Thierry Martins 069 */ 070@Name("versionedActions") 071@Scope(CONVERSATION) 072@Install(precedence = FRAMEWORK) 073public class VersionedActionsBean implements VersionedActions, Serializable { 074 075 private static final long serialVersionUID = 4472648747609642493L; 076 077 private static final Log log = LogFactory.getLog(VersionedActionsBean.class); 078 079 @In(create = true) 080 protected transient NavigationContext navigationContext; 081 082 /** @since 5.6 */ 083 @In(create = true, required = false) 084 protected transient DocumentsListsManager documentsListsManager; 085 086 @In(create = true, required = false) 087 protected transient CoreSession documentManager; 088 089 @In(create = true, required = false) 090 protected transient FacesMessages facesMessages; 091 092 @In(create = true, required = false) 093 protected transient ResourcesAccessor resourcesAccessor; 094 095 @In 096 protected transient Context sessionContext; 097 098 @In(create = true) 099 protected transient DocumentVersioning documentVersioning; 100 101 protected transient PageSelections<VersionModel> versionModelList; 102 103 protected String selectedVersionId; 104 105 protected String checkedOut; 106 107 @Create 108 @Override 109 public void initialize() { 110 } 111 112 @Observer(value = { DOCUMENT_SELECTION_CHANGED, DOCUMENT_CHANGED, DOCUMENT_SUBMITED_FOR_PUBLICATION, 113 DOCUMENT_PUBLISHED }, create = false) 114 @BypassInterceptors 115 @Override 116 public void resetVersions() { 117 versionModelList = null; 118 } 119 120 @Override 121 @Factory(value = "versionList", scope = EVENT) 122 public PageSelections<VersionModel> getVersionList() { 123 if (versionModelList == null || versionModelList.getEntries() == null 124 || versionModelList.getEntries().isEmpty()) { 125 retrieveVersions(); 126 } 127 return versionModelList; 128 } 129 130 @Override 131 public void retrieveVersions() { 132 /** 133 * in case the document is a proxy,meaning is the result of a publishing,to have the history of the document 134 * from which this proxy was created,first we have to get to the version that was created when the document was 135 * publish,and to which the proxy document indicates,and then from that version we have to get to the root 136 * document. 137 */ 138 DocumentModel currentDocument = navigationContext.getCurrentDocument(); 139 DocumentModel doc; 140 if (currentDocument.isProxy()) { 141 DocumentRef ref = currentDocument.getRef(); 142 DocumentModel version = documentManager.getSourceDocument(ref); 143 doc = documentManager.getSourceDocument(version.getRef()); 144 } else { 145 doc = currentDocument; 146 } 147 List<PageSelection<VersionModel>> versionModelSelections = new ArrayList<PageSelection<VersionModel>>(); 148 for (VersionModel versionModel : documentVersioning.getItemVersioningHistory(doc)) { 149 versionModelSelections.add(new PageSelection<VersionModel>(versionModel, isVersionSelected(versionModel))); 150 } 151 versionModelList = new PageSelections<VersionModel>(versionModelSelections); 152 } 153 154 /** 155 * Checks if the {@code versionModel} is selected. 156 * 157 * @param versionModel the version model 158 * @return true, if the {@versionModel} is selected 159 */ 160 protected boolean isVersionSelected(VersionModel versionModel) { 161 162 List<DocumentModel> currentVersionSelection = documentsListsManager.getWorkingList(DocumentsListsManager.CURRENT_VERSION_SELECTION); 163 if (currentVersionSelection != null) { 164 DocumentModel currentDocument = navigationContext.getCurrentDocument(); 165 if (currentDocument != null) { 166 DocumentModel version = documentManager.getDocumentWithVersion(currentDocument.getRef(), versionModel); 167 if (version != null) { 168 return currentVersionSelection.contains(version); 169 } 170 } 171 } 172 return false; 173 } 174 175 /** 176 * Restores the document to the selected version. If there is no selected version it does nothing. 177 * 178 * @return the page that needs to be displayed next 179 */ 180 @Override 181 public String restoreToVersion(VersionModel selectedVersion) { 182 DocumentModel restoredDocument = documentManager.restoreToVersion( 183 navigationContext.getCurrentDocument().getRef(), new IdRef(selectedVersion.getId()), true, true); 184 documentManager.save(); 185 186 // same as edit basically 187 // XXX AT: do edit events need to be sent? 188 EventManager.raiseEventsOnDocumentChange(restoredDocument); 189 return navigationContext.navigateToDocument(restoredDocument, "after-edit"); 190 } 191 192 @Override 193 public String restoreToVersion() { 194 if (getSelectedVersionId() != null) { 195 VersionModel selectedVersion = new VersionModelImpl(); 196 selectedVersion.setId(getSelectedVersionId()); 197 return restoreToVersion(selectedVersion); 198 } 199 return null; 200 } 201 202 @Override 203 public String viewArchivedVersion(VersionModel selectedVersion) { 204 return navigationContext.navigateToDocument(navigationContext.getCurrentDocument(), selectedVersion); 205 } 206 207 @Override 208 public String viewArchivedVersion() { 209 if (getSelectedVersionId() != null) { 210 VersionModel selectedVersion = new VersionModelImpl(); 211 selectedVersion.setId(getSelectedVersionId()); 212 return viewArchivedVersion(selectedVersion); 213 } 214 return null; 215 } 216 217 @Override 218 public boolean getCanRestore() { 219 // TODO: should check for a specific RESTORE permission instead 220 return documentManager.hasPermission(navigationContext.getCurrentDocument().getRef(), 221 SecurityConstants.WRITE_VERSION); 222 } 223 224 /** 225 * Tells if the current selected document is checked out or not. 226 */ 227 @Override 228 public String getCheckedOut() { 229 if (documentManager.isCheckedOut(navigationContext.getCurrentDocument().getRef())) { 230 checkedOut = "Checked-out"; 231 } else { 232 checkedOut = "Checked-in"; 233 } 234 return checkedOut; 235 } 236 237 @Override 238 public void setCheckedOut(String checkedOut) { 239 this.checkedOut = checkedOut; 240 } 241 242 /** 243 * Checks the document out. 244 * 245 * @return the next page 246 */ 247 @Override 248 public String checkOut() { 249 documentManager.checkOut(navigationContext.getCurrentDocument().getRef()); 250 return null; 251 } 252 253 /** 254 * Checks the selected document in, with the selected version. 255 */ 256 @Override 257 public String checkIn() { 258 DocumentModel currentDocument = navigationContext.getCurrentDocument(); 259 documentManager.checkIn(currentDocument.getRef(), null, null); 260 retrieveVersions(); 261 return navigationContext.getActionResult(currentDocument, UserAction.AFTER_EDIT); 262 } 263 264 @Override 265 public DocumentModel getSourceDocument() { 266 return getSourceDocument(navigationContext.getCurrentDocument()); 267 } 268 269 /** 270 * @since 5.4 271 */ 272 @Override 273 public DocumentModel getSourceDocument(DocumentModel document) { 274 return documentManager.getSourceDocument(document.getRef()); 275 } 276 277 @Override 278 public boolean canRemoveArchivedVersion(VersionModel selectedVersion) { 279 DocumentRef docRef = navigationContext.getCurrentDocument().getRef(); 280 DocumentModel docVersion = documentManager.getDocumentWithVersion(docRef, selectedVersion); 281 if (docVersion == null) { 282 // it doesn't exist? don't remove. Still it is a problem 283 log.warn("Unexpectedly couldn't find the version " + selectedVersion.getLabel()); 284 return false; 285 } 286 return documentManager.canRemoveDocument(docVersion.getRef()); 287 } 288 289 /** 290 * @since 5.6 291 */ 292 @Override 293 public boolean getCanRemoveSelectedArchivedVersions() { 294 List<DocumentModel> currentVersionSelection = documentsListsManager.getWorkingList(DocumentsListsManager.CURRENT_VERSION_SELECTION); 295 if (currentVersionSelection != null && currentVersionSelection.size() > 0) { 296 for (DocumentModel version : currentVersionSelection) { 297 if (!documentManager.canRemoveDocument(version.getRef())) { 298 return false; 299 } 300 } 301 return true; 302 } 303 return false; 304 } 305 306 @Override 307 public String removeArchivedVersion(VersionModel selectedVersion) { 308 DocumentRef docRef = navigationContext.getCurrentDocument().getRef(); 309 DocumentModel docVersion = documentManager.getDocumentWithVersion(docRef, selectedVersion); 310 if (docVersion == null) { 311 // it doesn't exist? consider removed 312 log.warn("Unexpectedly couldn't find the version " + selectedVersion.getLabel()); 313 return null; 314 } 315 documentManager.removeDocument(docVersion.getRef()); 316 documentManager.save(); 317 resetVersions(); 318 facesMessages.add(StatusMessage.Severity.INFO, 319 resourcesAccessor.getMessages().get("feedback.versioning.versionRemoved")); 320 return null; 321 } 322 323 /** 324 * @since 5.6 325 */ 326 @Override 327 public String removeSelectedArchivedVersions() { 328 329 List<DocumentModel> currentVersionSelection = documentsListsManager.getWorkingList(DocumentsListsManager.CURRENT_VERSION_SELECTION); 330 if (currentVersionSelection == null || currentVersionSelection.isEmpty()) { 331 log.warn("Currently selected version list is null or empty, cannot remove any version."); 332 return null; 333 } 334 for (DocumentModel version : currentVersionSelection) { 335 if (version != null) { 336 documentManager.removeDocument(version.getRef()); 337 } 338 } 339 documentManager.save(); 340 resetVersions(); 341 // remove from all lists 342 documentsListsManager.removeFromAllLists(new ArrayList<DocumentModel>(currentVersionSelection)); 343 facesMessages.add(StatusMessage.Severity.INFO, 344 resourcesAccessor.getMessages().get("feedback.versioning.versionsRemoved")); 345 return null; 346 } 347 348 @Override 349 public String getSelectedVersionId() { 350 return selectedVersionId; 351 } 352 353 @Override 354 public void setSelectedVersionId(String selectedVersionId) { 355 this.selectedVersionId = selectedVersionId; 356 } 357 358}