001/* 002 * (C) Copyright 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 * Antoine Taillefer 018 */ 019package org.nuxeo.ecm.diff.web; 020 021import static org.jboss.seam.ScopeType.CONVERSATION; 022import static org.jboss.seam.ScopeType.PAGE; 023 024import java.io.Serializable; 025import java.util.ArrayList; 026import java.util.List; 027 028import org.apache.commons.lang.StringUtils; 029import org.apache.commons.logging.Log; 030import org.apache.commons.logging.LogFactory; 031import org.jboss.seam.annotations.Factory; 032import org.jboss.seam.annotations.In; 033import org.jboss.seam.annotations.Name; 034import org.jboss.seam.annotations.Scope; 035import org.jboss.seam.international.LocaleSelector; 036import org.nuxeo.ecm.core.api.CoreSession; 037import org.nuxeo.ecm.core.api.DocumentModel; 038import org.nuxeo.ecm.core.api.IdRef; 039import org.nuxeo.ecm.core.api.NuxeoException; 040import org.nuxeo.ecm.core.api.VersionModel; 041import org.nuxeo.ecm.core.api.impl.VersionModelImpl; 042import org.nuxeo.ecm.diff.content.ContentDiffHelper; 043import org.nuxeo.ecm.diff.model.DiffDisplayBlock; 044import org.nuxeo.ecm.diff.model.DifferenceType; 045import org.nuxeo.ecm.diff.model.DocumentDiff; 046import org.nuxeo.ecm.diff.service.DiffDisplayService; 047import org.nuxeo.ecm.diff.service.DocumentDiffService; 048import org.nuxeo.ecm.platform.ui.web.api.NavigationContext; 049import org.nuxeo.ecm.webapp.documentsLists.DocumentsListsManager; 050import org.nuxeo.ecm.webapp.versioning.VersionedActions; 051import org.nuxeo.runtime.api.Framework; 052 053/** 054 * Handles document diff actions. 055 * 056 * @author <a href="mailto:ataillefer@nuxeo.com">Antoine Taillefer</a> 057 * @since 5.6 058 */ 059@Name("diffActions") 060@Scope(CONVERSATION) 061public class DiffActionsBean implements Serializable { 062 063 private static final long serialVersionUID = -5507491210664361778L; 064 065 private static final Log log = LogFactory.getLog(DiffActionsBean.class); 066 067 private static final String DOC_DIFF_VIEW = "view_doc_diff"; 068 069 private static final String CONTENT_DIFF_DIFFERENCE_TYPE_MSG_KEY_PREFIX = "diff.content.differenceType.message."; 070 071 private static final String LAST_VERSION_PROPERTY = "lastVersion"; 072 073 @In(create = true, required = false) 074 protected transient CoreSession documentManager; 075 076 @In(create = true, required = false) 077 protected transient NavigationContext navigationContext; 078 079 @In(create = true, required = false) 080 protected transient DocumentsListsManager documentsListsManager; 081 082 @In(create = true, required = false) 083 protected transient VersionedActions versionedActions; 084 085 @In(create = true) 086 protected transient LocaleSelector localeSelector; 087 088 protected DocumentModel leftDoc; 089 090 protected DocumentModel rightDoc; 091 092 protected String selectedVersionId; 093 094 protected String diffSelectionType = DiffSelectionType.content.name(); 095 096 /** 097 * Checks if the diff action is available for the {@link DocumentsListsManager#CURRENT_DOCUMENT_SELECTION} working 098 * list. 099 * 100 * @return true if can diff the current document selection 101 */ 102 public boolean getCanDiffCurrentDocumentSelection() { 103 104 return getCanDiffWorkingList(DocumentsListsManager.CURRENT_DOCUMENT_SELECTION); 105 } 106 107 /** 108 * Checks if the diff action is available for the {@link DocumentsListsManager#CURRENT_DOCUMENT_TRASH_SELECTION} 109 * working list. 110 * 111 * @return true if can diff the current document trash selection 112 */ 113 public boolean getCanDiffCurrentTrashSelection() { 114 115 return getCanDiffWorkingList(DocumentsListsManager.CURRENT_DOCUMENT_TRASH_SELECTION); 116 } 117 118 /** 119 * Checks if the diff action is available for the {@link DocumentsListsManager#CURRENT_DOCUMENT_SECTION_SELECTION} 120 * working list. 121 * 122 * @return true if can diff the current section selection 123 */ 124 public boolean getCanDiffCurrentSectionSelection() { 125 126 return getCanDiffWorkingList(DocumentsListsManager.CURRENT_DOCUMENT_SECTION_SELECTION); 127 } 128 129 /** 130 * Checks if the diff action is available for the {@link VersionDocumentsListsConstants#CURRENT_VERSION_SELECTION} 131 * working list. 132 * 133 * @return true if can diff the current version selection 134 */ 135 public boolean getCanDiffCurrentVersionSelection() { 136 137 return getCanDiffWorkingList(DocumentsListsManager.CURRENT_VERSION_SELECTION); 138 } 139 140 /** 141 * Checks if the diff action is available for the {@link DocumentsListsManager#DEFAULT_WORKING_LIST} working list. 142 * 143 * @return true if can diff the current default working list selection 144 */ 145 public boolean getCanDiffCurrentDefaultSelection() { 146 147 return getCanDiffWorkingList(DocumentsListsManager.DEFAULT_WORKING_LIST); 148 } 149 150 /** 151 * Checks if the diff action is available for the {@code listName} working list. 152 * <p> 153 * Condition: the working list has exactly 2 documents. 154 * 155 * @param listName the list name 156 * @return true if can diff the {@code listName} working list 157 */ 158 public boolean getCanDiffWorkingList(String listName) { 159 160 List<DocumentModel> currentSelectionWorkingList = documentsListsManager.getWorkingList(listName); 161 return currentSelectionWorkingList != null && currentSelectionWorkingList.size() == 2; 162 } 163 164 /** 165 * Prepares a diff of the current document selection. 166 * 167 * @return the view id 168 */ 169 public String prepareCurrentDocumentSelectionDiff() { 170 171 diffSelectionType = DiffSelectionType.content.name(); 172 return prepareWorkingListDiff(DocumentsListsManager.CURRENT_DOCUMENT_SELECTION); 173 } 174 175 /** 176 * Prepares a diff of the current document trash selection. 177 * 178 * @return the view id 179 */ 180 public String prepareCurrentTrashSelectionDiff() { 181 182 diffSelectionType = DiffSelectionType.trash.name(); 183 return prepareWorkingListDiff(DocumentsListsManager.CURRENT_DOCUMENT_TRASH_SELECTION); 184 } 185 186 /** 187 * Prepares a diff of the current section selection. 188 * 189 * @return the view id 190 */ 191 public String prepareCurrentSectionSelectionDiff() { 192 193 diffSelectionType = DiffSelectionType.content.name(); 194 return prepareWorkingListDiff(DocumentsListsManager.CURRENT_DOCUMENT_SECTION_SELECTION); 195 } 196 197 /** 198 * Prepares a diff of the current version selection. 199 * 200 * @return the view id 201 */ 202 public String prepareCurrentVersionSelectionDiff() { 203 204 diffSelectionType = DiffSelectionType.version.name(); 205 return prepareWorkingListDiff(DocumentsListsManager.CURRENT_VERSION_SELECTION); 206 } 207 208 /** 209 * Prepares a diff of the current default selection. 210 * 211 * @return the view id 212 */ 213 public String prepareCurrentDefaultSelectionDiff() { 214 215 diffSelectionType = DiffSelectionType.content.name(); 216 return prepareWorkingListDiff(DocumentsListsManager.DEFAULT_WORKING_LIST); 217 } 218 219 /** 220 * Prepares a diff of the {@code listName} working list. 221 * 222 * @return the view id 223 */ 224 public String prepareWorkingListDiff(String listName) { 225 226 List<DocumentModel> workingList = getWorkingList(listName); 227 228 leftDoc = workingList.get(0); 229 rightDoc = workingList.get(1); 230 231 return refresh(); 232 } 233 234 /** 235 * Prepare a diff of the current document with a specific version 236 * 237 * @param versionLabel version label to look for, if you want the last version use org.nuxeo.ecm.diff.web 238 * .DiffActionsBean#LAST_VERSION_PROPERTY 239 */ 240 public String prepareCurrentVersionDiff(String versionLabel) { 241 if (StringUtils.isBlank(versionLabel)) { 242 versionLabel = LAST_VERSION_PROPERTY; 243 } 244 245 DocumentModel currentDocument = navigationContext.getCurrentDocument(); 246 if (currentDocument.isVersion()) { 247 log.info("Unable to diff, current document is a version document"); 248 return null; 249 } 250 251 DocumentModel documentVersion; 252 if (LAST_VERSION_PROPERTY.equals(versionLabel)) { 253 documentVersion = documentManager.getLastDocumentVersion(currentDocument.getRef()); 254 255 if (documentVersion == null) { 256 log.info("Unable to diff, current document do not have any versions yet."); 257 return null; 258 } 259 } else { 260 VersionModel versionModel = new VersionModelImpl(); 261 versionModel.setLabel(versionLabel); 262 documentVersion = documentManager.getDocumentWithVersion(currentDocument.getRef(), versionModel); 263 264 if (documentVersion == null) { 265 log.info("Unable to found " + versionLabel + " on current document to diff."); 266 return null; 267 } 268 } 269 270 setLeftDoc(currentDocument); 271 setRightDoc(documentVersion); 272 273 diffSelectionType = DiffSelectionType.version.name(); 274 275 return DOC_DIFF_VIEW; 276 } 277 278 /** 279 * Prepares a diff of the selected version with the live doc. 280 * 281 * @return the view id 282 */ 283 public String prepareCurrentVersionDiff() { 284 285 String selectedVersionId = versionedActions.getSelectedVersionId(); 286 if (selectedVersionId != null) { 287 DocumentModel currentDocument = navigationContext.getCurrentDocument(); 288 if (currentDocument == null) { 289 throw new NuxeoException( 290 "Cannot make a diff between selected version and current document since current document is null."); 291 } 292 293 VersionModel selectedVersion = new VersionModelImpl(); 294 selectedVersion.setId(selectedVersionId); 295 DocumentModel docVersion = documentManager.getDocumentWithVersion(currentDocument.getRef(), selectedVersion); 296 if (docVersion == null) { 297 throw new NuxeoException( 298 "Cannot make a diff between selected version and current document since selected version document is null."); 299 } 300 301 leftDoc = docVersion; 302 rightDoc = currentDocument; 303 304 diffSelectionType = DiffSelectionType.version.name(); 305 306 return DOC_DIFF_VIEW; 307 } 308 return null; 309 } 310 311 /** 312 * Refreshes the diff between leftDoc and rightDoc. 313 * 314 * @return the view id 315 */ 316 public String refresh() { 317 318 // Fetch docs from repository 319 if (isDocumentDiffAvailable()) { 320 leftDoc = documentManager.getDocument(leftDoc.getRef()); 321 rightDoc = documentManager.getDocument(rightDoc.getRef()); 322 } 323 324 return DOC_DIFF_VIEW; 325 } 326 327 /** 328 * Checks if document diff is available. 329 * 330 * @return true, if is document diff available 331 */ 332 public boolean isDocumentDiffAvailable() { 333 return leftDoc != null && rightDoc != null; 334 } 335 336 /** 337 * Gets the document diff. 338 * 339 * @return the document diff between leftDoc and rightDoc if leftDoc and rightDoc aren't null, else null 340 */ 341 @Factory(value = "defaultDiffDisplayBlocks", scope = PAGE) 342 public List<DiffDisplayBlock> getDefaultDiffDisplayBlocks() { 343 344 if (leftDoc == null || rightDoc == null) { 345 return new ArrayList<DiffDisplayBlock>(); 346 } 347 348 DocumentDiff docDiff = getDocumentDiffService().diff(documentManager, leftDoc, rightDoc); 349 return getDiffDisplayService().getDiffDisplayBlocks(docDiff, leftDoc, rightDoc); 350 } 351 352 /** 353 * Gets the content diff fancybox URL for the property with xpath {@code propertyXPath}. 354 * 355 * @param propertyLabel the property label 356 * @param propertyXPath the property xpath 357 * @return the content diff fancybox URL 358 */ 359 public String getContentDiffFancyBoxURL(String propertyLabel, String propertyXPath) { 360 361 return getContentDiffFancyBoxURL(propertyLabel, propertyXPath, null); 362 } 363 364 /** 365 * Gets the content diff fancybox URL for the property with xpath {@code propertyXPath} using {@code conversionType} 366 * . 367 * 368 * @param propertyLabel the property label 369 * @param propertyXPath the property xpath 370 * @param conversionType the conversion type 371 * @return the content diff fancybox URL 372 */ 373 public String getContentDiffFancyBoxURL(String propertyLabel, String propertyXPath, String conversionType) 374 { 375 376 if (StringUtils.isEmpty(propertyXPath)) { 377 log.error("Cannot get content diff fancybox URL with a null propertyXPath."); 378 return null; 379 } 380 return ContentDiffHelper.getContentDiffFancyBoxURL(navigationContext.getCurrentDocument(), propertyLabel, 381 propertyXPath, conversionType); 382 } 383 384 /** 385 * Gets the content diff URL of two documents independently of the current document 386 * 387 * @param docLeftId a DocumentModel id, not a path. 388 * @param docRightId a DocumentModel id, not a path. 389 * @param propertyXPath 390 * @param conversionTypeParam 391 * @return 392 */ 393 public String getContentDiffURL(String docLeftId, String docRightId, String propertyXPath, 394 String conversionTypeParam) { 395 DocumentModel leftDoc = null; 396 DocumentModel rightDoc = null; 397 if (!StringUtils.isBlank(docLeftId)) { 398 leftDoc = documentManager.getDocument(new IdRef(docLeftId)); 399 } 400 401 if (!StringUtils.isBlank(docRightId)) { 402 rightDoc = documentManager.getDocument(new IdRef(docRightId)); 403 } 404 405 if (rightDoc == null || leftDoc == null) { 406 log.error("Cannot get content diff URL with a null leftDoc or a null rightDoc."); 407 return null; 408 } 409 410 if (StringUtils.isEmpty(propertyXPath)) { 411 log.error("Cannot get content diff URL with a null schemaName or a null fieldName."); 412 return null; 413 } 414 415 String conversionType = null; 416 if (!StringUtils.isEmpty(conversionTypeParam)) { 417 conversionType = conversionTypeParam; 418 } 419 420 return ContentDiffHelper.getContentDiffURL(navigationContext.getCurrentDocument().getRepositoryName(), leftDoc, 421 rightDoc, propertyXPath, conversionType, localeSelector.getLocaleString()); 422 } 423 424 /** 425 * Gets the content diff URL. 426 * 427 * @param propertyXPath the property xpath 428 * @param conversionTypeParam the conversion type param 429 * @return the content diff URL 430 */ 431 public String getContentDiffURL(String propertyXPath, String conversionTypeParam) { 432 433 if (leftDoc == null || rightDoc == null) { 434 log.error("Cannot get content diff URL with a null leftDoc or a null rightDoc."); 435 return null; 436 } 437 if (StringUtils.isEmpty(propertyXPath)) { 438 log.error("Cannot get content diff URL with a null schemaName or a null fieldName."); 439 return null; 440 } 441 String conversionType = null; 442 if (!StringUtils.isEmpty(conversionTypeParam)) { 443 conversionType = conversionTypeParam; 444 } 445 return ContentDiffHelper.getContentDiffURL(navigationContext.getCurrentDocument().getRepositoryName(), leftDoc, 446 rightDoc, propertyXPath, conversionType, localeSelector.getLocaleString()); 447 } 448 449 /** 450 * Gets the content diff with blob post processing URL. 451 * 452 * @param propertyXPath the property xpath 453 * @param conversionTypeParam the conversion type param 454 * @return the content diff with blob post processing URL 455 */ 456 public String getContentDiffWithBlobPostProcessingURL(String propertyXPath, String conversionTypeParam) { 457 return getContentDiffURL(propertyXPath, conversionTypeParam) + "?blobPostProcessing=true"; 458 } 459 460 /** 461 * Checks if is different filename. 462 */ 463 public boolean isDifferentFilename(DifferenceType differenceType) { 464 return DifferenceType.differentFilename.equals(differenceType); 465 } 466 467 /** 468 * Gets the content diff difference type message key. 469 */ 470 public String getContentDiffDifferenceTypeMsgKey(DifferenceType differenceType) { 471 return CONTENT_DIFF_DIFFERENCE_TYPE_MSG_KEY_PREFIX + differenceType.name(); 472 } 473 474 /** 475 * Gets the {@code listName} working list. 476 * 477 * @return the {@code listName} working list 478 */ 479 protected final List<DocumentModel> getWorkingList(String listName) { 480 481 List<DocumentModel> currentSelectionWorkingList = documentsListsManager.getWorkingList(listName); 482 483 if (currentSelectionWorkingList == null || currentSelectionWorkingList.size() != 2) { 484 throw new NuxeoException(String.format( 485 "Cannot make a diff of the %s working list: need to have exactly 2 documents in the working list.", 486 listName)); 487 } 488 return currentSelectionWorkingList; 489 } 490 491 /** 492 * Gets the document diff service. 493 * 494 * @return the document diff service 495 */ 496 protected final DocumentDiffService getDocumentDiffService() { 497 return Framework.getService(DocumentDiffService.class); 498 } 499 500 /** 501 * Gets the diff display service. 502 * 503 * @return the diff display service 504 */ 505 protected final DiffDisplayService getDiffDisplayService() { 506 return Framework.getService(DiffDisplayService.class); 507 } 508 509 public DocumentModel getLeftDoc() { 510 return leftDoc; 511 } 512 513 public void setLeftDoc(DocumentModel leftDoc) { 514 this.leftDoc = leftDoc; 515 } 516 517 public DocumentModel getRightDoc() { 518 return rightDoc; 519 } 520 521 public void setRightDoc(DocumentModel rightDoc) { 522 this.rightDoc = rightDoc; 523 } 524 525 public String getDiffSelectionType() { 526 return diffSelectionType; 527 } 528 529 public void setDiffSelectionType(String diffSelectionType) { 530 this.diffSelectionType = diffSelectionType; 531 } 532}