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