001/* 002 * (C) Copyright 2006-2016 Nuxeo (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 * Bogdan Stefanescu 018 * Florent Guillaume 019 */ 020package org.nuxeo.ecm.core.api; 021 022import java.io.Serializable; 023import java.security.Principal; 024import java.util.Arrays; 025import java.util.Collection; 026import java.util.List; 027import java.util.Map; 028 029import org.nuxeo.ecm.core.api.DocumentModel.DocumentModelRefresh; 030import org.nuxeo.ecm.core.api.event.DocumentEventTypes; 031import org.nuxeo.ecm.core.api.security.ACE; 032import org.nuxeo.ecm.core.api.security.ACP; 033import org.nuxeo.ecm.core.schema.DocumentType; 034import org.nuxeo.ecm.core.schema.types.Schema; 035 036/** 037 * A session to the Nuxeo Core. 038 * 039 * @see DocumentModel 040 * @see DocumentRef 041 * @author Bogdan Stefanescu 042 * @author Florent Guillaume 043 */ 044public interface CoreSession extends AutoCloseable { 045 046 // used to pass properties to importDocument 047 String IMPORT_VERSION_VERSIONABLE_ID = "ecm:versionableId"; 048 049 String IMPORT_VERSION_CREATED = "ecm:versionCreated"; 050 051 String IMPORT_VERSION_LABEL = "ecm:versionLabel"; 052 053 String IMPORT_VERSION_DESCRIPTION = "ecm:versionDescription"; 054 055 String IMPORT_VERSION_IS_LATEST = "ecm:isLatestVersion"; 056 057 String IMPORT_VERSION_IS_LATEST_MAJOR = "ecm:isLatestMajorVersion"; 058 059 String IMPORT_IS_VERSION = "ecm:isVersion"; 060 061 String IMPORT_VERSION_MAJOR = "ecm:majorVersion"; 062 063 String IMPORT_VERSION_MINOR = "ecm:minorVersion"; 064 065 String IMPORT_PROXY_TARGET_ID = "ecm:proxyTargetId"; 066 067 String IMPORT_PROXY_VERSIONABLE_ID = "ecm:proxyVersionableId"; 068 069 String IMPORT_LIFECYCLE_POLICY = "ecm:lifeCyclePolicy"; 070 071 String IMPORT_LIFECYCLE_STATE = "ecm:lifeCycleState"; 072 073 /** @since 5.4.2 */ 074 String IMPORT_LOCK_OWNER = "ecm:lockOwner"; 075 076 /** 077 * Lock creation time as a Calendar object. 078 * 079 * @since 5.4.2 080 */ 081 String IMPORT_LOCK_CREATED = "ecm:lockCreated"; 082 083 String IMPORT_CHECKED_IN = "ecm:isCheckedIn"; 084 085 String IMPORT_BASE_VERSION_ID = "ecm:baseVersionId"; 086 087 /** The document type to use to create a proxy by import. */ 088 String IMPORT_PROXY_TYPE = "ecm:proxy"; 089 090 /** 091 * Skip the check to see if a destination exists on importDocument and createDocument 092 * 093 * @since 9.1 094 **/ 095 String SKIP_DESTINATION_CHECK_ON_CREATE = "skipDestinationCheck"; 096 097 /** 098 * Allow version write, Boolean parameter passed in context data at saveDocument time. 099 * 100 * @since 5.9.2 101 */ 102 String ALLOW_VERSION_WRITE = "allowVersionWrite"; 103 104 /** 105 * A context data key which represents the source of current session calls. For example: 106 * <ul> 107 * <li>fileimporter-NoteImporter</li> 108 * <li>drive</li> 109 * <li>rest</li> 110 * </ul> 111 * 112 * @since 9.1 113 */ 114 String SOURCE = "source"; 115 116 /** 117 * Change token, a String parameter passed in context data at {@link #saveDocument} time. 118 * 119 * @see DocumentModel#putContextData 120 * @see #getChangeToken 121 * @see DocumentModel#getChangeToken 122 * @since 9.1 123 */ 124 String CHANGE_TOKEN = "changeToken"; 125 126 /** 127 * Closes this session. 128 * 129 * @since 5.9.3 130 */ 131 @Override 132 void close(); 133 134 /** 135 * Destroys any system resources held by this instance. 136 * <p> 137 * Called when the instance is no more needed. 138 */ 139 void destroy(); 140 141 /** 142 * Gets the document type object given its type name. 143 * 144 * @param type the document type name 145 * @return the type the doc type object 146 */ 147 DocumentType getDocumentType(String type); 148 149 /** 150 * Returns true if the session is currently connected to the repository. 151 */ 152 boolean isLive(boolean onThread); 153 154 /** 155 * Cancels any pending change made through this session. 156 */ 157 void cancel(); 158 159 /** 160 * Saves any pending changes done until now through this session. 161 */ 162 void save(); 163 164 /** 165 * Gets the current session id. 166 * <p> 167 * If the client is not connected returns null. 168 * 169 * @return the session id or null if not connected 170 */ 171 String getSessionId(); 172 173 /** 174 * Returns {@code true} if all sessions in the current thread share the same state. 175 * 176 * @deprecated since 8.4 as it always returns true by design 177 */ 178 @Deprecated 179 boolean isStateSharedByAllThreadSessions(); 180 181 /** 182 * Gets the principal that created the client session. 183 * 184 * @return the principal 185 */ 186 Principal getPrincipal(); 187 188 /** 189 * Checks if the principal that created the client session has the given privilege on the referred document. 190 */ 191 boolean hasPermission(DocumentRef docRef, String permission); 192 193 /** 194 * Checks if a given principal has the given privilege on the referred document. 195 */ 196 boolean hasPermission(Principal principal, DocumentRef docRef, String permission); 197 198 /** 199 * Filters the supplied permissions based on whether they are granted to a given principal for a given document. 200 * 201 * @since 9.1 202 */ 203 Collection<String> filterGrantedPermissions(Principal principal, DocumentRef docRef, 204 Collection<String> permissions); 205 206 /** 207 * Gets the root document of this repository. 208 * 209 * @return the root document. cannot be null 210 */ 211 DocumentModel getRootDocument(); 212 213 /** 214 * Gets a document model given its reference. 215 * <p> 216 * The default schemas are used to populate the returned document model. Default schemas are configured via the 217 * document type manager. 218 * <p> 219 * Any other data model not part of the default schemas will be lazily loaded as needed. 220 * 221 * @param docRef the document reference 222 * @return the document 223 * @throws DocumentNotFoundException if the document cannot be found 224 */ 225 DocumentModel getDocument(DocumentRef docRef) throws DocumentNotFoundException; 226 227 /** 228 * Gets a list of documents given their references. 229 * <p> 230 * Documents that are not accessible are skipped. 231 * 232 * @throws DocumentNotFoundException if a document cannot be found 233 */ 234 DocumentModelList getDocuments(DocumentRef[] docRefs) throws DocumentNotFoundException; 235 236 /** 237 * Gets a child document given its name and the parent reference. 238 * <p> 239 * Throws an exception if the document could not be found. 240 * <p> 241 * If the supplied id is null, returns the default child of the document if any, otherwise raises an exception. 242 * <p> 243 * If the parent is null or its path is null, then root is considered. 244 * 245 * @param parent the reference to the parent document 246 * @param name the name of the child document to retrieve 247 * @return the named child if exists 248 * @throws DocumentNotFoundException if there is no child with the given name 249 */ 250 DocumentModel getChild(DocumentRef parent, String name); 251 252 /** 253 * Tests if the document has a child with the given name. 254 * <p> 255 * This operation silently ignores non-folder documents: If the document is not a folder then returns false. 256 * 257 * @param parent the document 258 * @param name the child name 259 * @return {@code true} if the document has a child with the given name 260 * @since 7.3 261 */ 262 boolean hasChild(DocumentRef parent, String name); 263 264 /** 265 * Gets the children of the given parent. 266 * 267 * @param parent the parent reference 268 * @return the children if any, an empty list if no children or null if the specified parent document is not a 269 * folder 270 */ 271 DocumentModelList getChildren(DocumentRef parent); 272 273 /** 274 * Gets an iterator to the children of the given parent. 275 * 276 * @param parent the parent reference 277 * @return iterator over the children collection or null if the specified parent document is not a folder 278 */ 279 DocumentModelIterator getChildrenIterator(DocumentRef parent); 280 281 /** 282 * Gets the children of the given parent filtered according to the given document type. 283 * 284 * @param parent the parent reference 285 * @param type the wanted document type 286 * @return the documents if any, an empty list if none were found or null if the parent document is not a folder 287 */ 288 DocumentModelList getChildren(DocumentRef parent, String type); 289 290 /** 291 * Gets an iterator to the children of the given parent filtered according to the given document type. 292 */ 293 DocumentModelIterator getChildrenIterator(DocumentRef parent, String type); 294 295 /** 296 * Gets the children of the given parent filtered according to the given document type and permission. 297 * 298 * @param parent the parent reference 299 * @param type the wanted document type 300 * @param perm the permission the user must have 301 * @return the documents if any, an empty list if none were found or null if the parent document is not a folder 302 */ 303 DocumentModelList getChildren(DocumentRef parent, String type, String perm); 304 305 /** 306 * Same as {@link #getChildren(DocumentRef, String, String)} but the result is filtered and then sorted using the 307 * specified filter and sorter. 308 * 309 * @param parent the parent reference 310 * @param type the wanted type 311 * @param perm permission to check for. If null, defaults to READ 312 * @param filter the filter to use if any, null otherwise 313 * @param sorter the sorter to use if any, null otherwise 314 * @return the list of the children or an empty list if no children were found or null if the given parent is not a 315 * folder 316 */ 317 DocumentModelList getChildren(DocumentRef parent, String type, String perm, Filter filter, Sorter sorter); 318 319 /** 320 * Gets the references of the children. No permission is checked if perm is null. 321 * 322 * @param parentRef the parent reference 323 * @param perm the permission to check on the children (usually READ); if null, <b>no permission is checked</b> 324 * @return a list of children references 325 * @since 1.4.1 326 */ 327 List<DocumentRef> getChildrenRefs(DocumentRef parentRef, String perm); 328 329 /** 330 * Gets the children of the given parent filtered according to the given document type and permission. Long result 331 * sets are loaded frame by frame transparently by the DocumentModelIterator. 332 */ 333 DocumentModelIterator getChildrenIterator(DocumentRef parent, String type, String perm, Filter filter); 334 335 /** 336 * Same as {@link #getChildren(DocumentRef, String, String, Filter, Sorter)} without specific permission filtering. 337 * 338 * @param parent the parent reference 339 * @param type the wanted type 340 * @param filter the filter to use if any, null otherwise 341 * @param sorter the sorter to use if any, null otherwise 342 * @return the list of the children or an empty list if no children were found or null if the given parent is not a 343 * folder 344 */ 345 DocumentModelList getChildren(DocumentRef parent, String type, Filter filter, Sorter sorter); 346 347 /** 348 * Same as {@link CoreSession#getChildren(DocumentRef)} but returns only folder documents. 349 * 350 * @param parent the parent ref 351 * @return a list of children if any, an empty one if none or null if the given parent is not a folder 352 */ 353 DocumentModelList getFolders(DocumentRef parent); 354 355 /** 356 * Same as {@link CoreSession#getFolders(DocumentRef)} but uses an optional filter and sorter on the result. 357 * 358 * @param parent the parent reference 359 * @param filter the filter to use or null if none 360 * @param sorter the sorter to use or null if none 361 * @return a list of children if any, an empty one if none or null if the given parent is not a folder 362 */ 363 DocumentModelList getFolders(DocumentRef parent, Filter filter, Sorter sorter); 364 365 /** 366 * Same as {@link CoreSession#getChildren(DocumentRef)} but returns only non-folder documents. 367 * 368 * @param parent the parent reference 369 * @return a list of children if any, an empty one if none or null if the given parent is not a folder 370 */ 371 DocumentModelList getFiles(DocumentRef parent); 372 373 /** 374 * Same as {@link #getFiles} but uses an optional filter and sorter on the result. 375 * 376 * @param parent the parent reference 377 * @param filter the filter to use or null if none 378 * @param sorter the sorter to use or null if none 379 * @return a list of children if any, an empty one if none or null if the given parent is not a folder 380 */ 381 DocumentModelList getFiles(DocumentRef parent, Filter filter, Sorter sorter); 382 383 /** 384 * Returns the parent ref of the document referenced by {@code docRef} or {@code null} if this is the root document. 385 * <p> 386 * This method does not check the permissions on the parent document of this {@code CoreSession}'s {@code Principal} 387 * . 388 * 389 * @since 5.4.2 390 */ 391 DocumentRef getParentDocumentRef(DocumentRef docRef); 392 393 /** 394 * Gets the parent document or null if this is the root document. 395 * 396 * @return the parent document or null if this is the root document 397 */ 398 DocumentModel getParentDocument(DocumentRef docRef); 399 400 /** 401 * Gets the parent documents in path from the root to the given document or empty list if this is the root document. 402 * <p> 403 * Documents the principal is is not allowed to browse are filtered out the parents list. 404 * 405 * @return the list with parent documents or empty list if this is the root document 406 */ 407 List<DocumentModel> getParentDocuments(DocumentRef docRef); 408 409 /** 410 * Tests if the document pointed by the given reference exists and is accessible. 411 * <p> 412 * This operation makes no difference between non-existence and permission problems. 413 * <p> 414 * If the parent is null or its path is null, then root is considered. 415 * 416 * @param docRef the reference to the document to test for existence 417 * @return true if the referenced document exists, false otherwise 418 */ 419 boolean exists(DocumentRef docRef); 420 421 /** 422 * Tests if the document has any children. 423 * <p> 424 * This operation silently ignores non-folder documents: If the document is not a folder then returns false. 425 * <p> 426 * If the parent is null or its path is null, then root is considered. 427 * 428 * @param docRef the reference to the document to test 429 * @return true if document has children, false otherwise 430 */ 431 boolean hasChildren(DocumentRef docRef); 432 433 /** 434 * Creates a document model using type name. 435 * <p> 436 * Used to fetch initial datamodels from the type definition. 437 * <p> 438 * DocumentModel creation notifies a {@link DocumentEventTypes#EMPTY_DOCUMENTMODEL_CREATED} so that core event 439 * listener can initialize its content with computed properties. 440 * 441 * @return the initial document model 442 */ 443 DocumentModel createDocumentModel(String typeName); 444 445 /** 446 * Creates a document model using required information. 447 * <p> 448 * Used to fetch initial datamodels from the type definition. 449 * <p> 450 * DocumentModel creation notifies a {@link DocumentEventTypes#EMPTY_DOCUMENTMODEL_CREATED} so that core event 451 * listener can initialize its content with computed properties. 452 * 453 * @param parentPath the parent path 454 * @param name The destination name 455 * @param typeName the type name 456 * @return the initial document model 457 */ 458 DocumentModel createDocumentModel(String parentPath, String name, String typeName); 459 460 /** 461 * Creates a document model using required information. 462 * <p> 463 * Used to fetch initial datamodels from the type definition. 464 * <p> 465 * DocumentModel creation notifies a {@link DocumentEventTypes#EMPTY_DOCUMENTMODEL_CREATED} so that core event 466 * listener can initialize its content with computed properties. 467 * 468 * @param typeName the type name 469 * @param options additional contextual data provided to core event listeners 470 * @return the initial document model 471 */ 472 DocumentModel createDocumentModel(String typeName, Map<String, Object> options); 473 474 /** 475 * Creates a document using given document model for initialization. 476 * <p> 477 * The model contains path of the new document, its type and optionally the initial data models of the document. 478 * <p> 479 * 480 * @param model the document model to use for initialization 481 * @return the created document 482 */ 483 DocumentModel createDocument(DocumentModel model); 484 485 /** 486 * Bulk creation of documents. 487 * 488 * @param docModels the document models to use for intialization 489 * @return the created documents 490 */ 491 DocumentModel[] createDocument(DocumentModel[] docModels); 492 493 /** 494 * Low-level import of documents, reserved for the administrator. 495 * <p> 496 * This method is used to import documents with given ids, or directly import versions and proxies. 497 * <p> 498 * The id, parent, name and typeName must be present in each docModel. 499 * <p> 500 * The context data needs to be filled with values depending on the type of the document: 501 * <p> 502 * For a proxy (type = {@code "ecm:proxyType"}): {@link #IMPORT_PROXY_TARGET_ID} and 503 * {@link #IMPORT_PROXY_VERSIONABLE_ID}. 504 * <p> 505 * For a version (no parent): {@link #IMPORT_VERSION_VERSIONABLE_ID}, {@link #IMPORT_VERSION_CREATED}, 506 * {@link #IMPORT_VERSION_LABEL} and {@link #IMPORT_VERSION_DESCRIPTION}. 507 * <p> 508 * For a live document: {@link #IMPORT_BASE_VERSION_ID} and {@link #IMPORT_CHECKED_IN} (Boolean). 509 * <p> 510 * For a live document or a version: {@link #IMPORT_LIFECYCLE_POLICY} , {@link #IMPORT_LIFECYCLE_STATE}, 511 * {@link #IMPORT_VERSION_MAJOR} (Long) and {@link #IMPORT_VERSION_MINOR} (Long). 512 * 513 * @param docModels the documents to create 514 */ 515 void importDocuments(List<DocumentModel> docModels); 516 517 /** 518 * Saves changes done on the given document model. 519 * 520 * @param docModel the document model that needs modified 521 */ 522 DocumentModel saveDocument(DocumentModel docModel); 523 524 /** 525 * Bulk document saving. 526 * 527 * @param docModels the document models that needs to be saved 528 */ 529 void saveDocuments(DocumentModel[] docModels); 530 531 /** 532 * Check if a document can be removed. This needs the REMOVE permission on the document and the REMOVE_CHILDREN 533 * permission on the parent. 534 * <p> 535 * For an archived version to be removeable, it must not be referenced from any proxy or be the base of a working 536 * document, and the REMOVE permission must be available on the working document (or the user must be an 537 * administrator if no working document exists). 538 * 539 * @param docRef the document 540 * @return true if the document can be removed 541 */ 542 boolean canRemoveDocument(DocumentRef docRef); 543 544 /** 545 * Removes this document and all its children, if any. 546 * 547 * @param docRef the reference to the document to remove 548 */ 549 void removeDocument(DocumentRef docRef); 550 551 /** 552 * Bulk method to remove documents. 553 * <p> 554 * This method is safe with respect to orderings: it doesn't fail if an ancestor of a document occurs before the 555 * document. 556 * </p> 557 * 558 * @param docRefs the refs to the document to remove 559 */ 560 void removeDocuments(DocumentRef[] docRefs); 561 562 /** 563 * Removes all children from the given document. 564 * 565 * @param docRef the reference to the document to remove 566 */ 567 void removeChildren(DocumentRef docRef); 568 569 /** 570 * Copies the source document to the destination folder under the given name. If the name is null the original name 571 * is preserved. 572 * <p> 573 * If the destination document is not a folder or it doesn't exists then throws an exception. 574 * <p> 575 * If the source is a proxy the destination will be a copy of the proxy. 576 * 577 * @param src the source document reference 578 * @param dst the destination folder reference 579 * @param name the new name of the file or null if the original name must be preserved 580 * @param copyOptions the options for copy 581 */ 582 DocumentModel copy(DocumentRef src, DocumentRef dst, String name, CopyOption... copyOptions); 583 584 /** 585 * Copies the source document to the destination folder under the given name. If the name is null the original name 586 * is preserved. 587 * <p> 588 * If the destination document is not a folder or it doesn't exists then throws an exception. 589 * <p> 590 * If the source is a proxy the destination will be a copy of the proxy. 591 * 592 * @param src the source document reference 593 * @param dst the destination folder reference 594 * @param name the new name of the file or null if the original name must be preserved 595 * @param resetLifeCycle the property that flagged whether reset destination document lifecycle or not 596 * @since 5.7 597 * @deprecated Since 8.2. Use {@link #copy(DocumentRef, DocumentRef, String, CopyOption...)} instead 598 */ 599 @Deprecated 600 DocumentModel copy(DocumentRef src, DocumentRef dst, String name, boolean resetLifeCycle); 601 602 /** 603 * Bulk copy. Destination must be a folder document. 604 * 605 * @param src the documents to copy 606 * @param dst the destination folder 607 * @param copyOptions the options for copy 608 * @since 8.2 609 */ 610 List<DocumentModel> copy(List<DocumentRef> src, DocumentRef dst, CopyOption... copyOptions); 611 612 /** 613 * Bulk copy. Destination must be a folder document. 614 * 615 * @param src the documents to copy 616 * @param dst the destination folder 617 * @param resetLifeCycle the property that flagged whether reset destination document lifecycle or not 618 * @since 5.7 619 * @deprecated Since 8.2. Use {@link #copy(List, DocumentRef, CopyOption...)} instead 620 */ 621 @Deprecated 622 List<DocumentModel> copy(List<DocumentRef> src, DocumentRef dst, boolean resetLifeCycle); 623 624 /** 625 * Work like copy but in the case of a source proxy the destination will be a new document instead of a proxy. 626 * 627 * @see CoreSession#copy(DocumentRef, DocumentRef, String, CopyOption...) 628 * @param src the source document reference 629 * @param dst the destination folder reference 630 * @param name the new name of the file or null if the original name must be preserved 631 * @param copyOptions the options for copy 632 * @since 8.2 633 */ 634 DocumentModel copyProxyAsDocument(DocumentRef src, DocumentRef dst, String name, CopyOption... copyOptions); 635 636 /** 637 * Work like copy but in the case of a source proxy the destination will be a new document instead of a proxy. 638 * 639 * @param src the source document reference 640 * @param dst the destination folder reference 641 * @param name the new name of the file or null if the original name must be preserved 642 * @param resetLifeCycle the property that flagged whether reset destination document lifecycle or not 643 * @since 5.7 644 * @deprecated Since 8.2. Use {@link #copyProxyAsDocument(DocumentRef, DocumentRef, String, CopyOption...)} instead 645 */ 646 @Deprecated 647 DocumentModel copyProxyAsDocument(DocumentRef src, DocumentRef dst, String name, boolean resetLifeCycle); 648 649 /** 650 * Bulk copyProxyAsDocument. Destination must be a folder document. 651 * 652 * @param src the documents to copy 653 * @param dst the destination folder 654 * @param copyOptions the options of copy 655 * @since 8.2 656 */ 657 List<DocumentModel> copyProxyAsDocument(List<DocumentRef> src, DocumentRef dst, CopyOption... copyOptions); 658 659 /** 660 * Bulk copyProxyAsDocument. Destination must be a folder document. 661 * 662 * @param src the documents to copy 663 * @param dst the destination folder 664 * @param resetLifeCycle the property that flagged whether reset destination document lifecycle or not 665 * @since 5.7 666 * @deprecated Since 8.2. Use {@link #copyProxyAsDocument(List, DocumentRef, CopyOption...)} instead 667 */ 668 @Deprecated 669 List<DocumentModel> copyProxyAsDocument(List<DocumentRef> src, DocumentRef dst, boolean resetLifeCycle); 670 671 /** 672 * Moves the source document to the destination folder under the given name. If the name is {@code null} or if there 673 * is a collision, a suitable new name is found. 674 * <p> 675 * If the destination document is not a folder or it doesn't exists then throws an exception. 676 * 677 * @param src the source document reference 678 * @param dst the destination folder reference 679 * @param name the new name of the file, or {@code null} 680 */ 681 DocumentModel move(DocumentRef src, DocumentRef dst, String name); 682 683 /** 684 * Bulk move. Destination must be a folder document. 685 * 686 * @param src the documents to move 687 * @param dst the destination folder 688 */ 689 void move(List<DocumentRef> src, DocumentRef dst); 690 691 /** 692 * Gets the document access control policy. 693 * <p> 694 * The returned ACP is the ACP defined on that document if any + the inherited ACL if any. If neither a local ACP 695 * nor inherited ACL exists null is returned. 696 * <p> 697 * Note that modifying the returned ACP will not affect in any way the stored document ACP. To modify the ACP you 698 * must explicitely set it by calling {@link CoreSession#setACP(DocumentRef, ACP, boolean)} 699 * <p> 700 * This method will always fetch a fresh ACP from the storage. The recommended way to get the ACP is to use 701 * {@link DocumentModel#getACP()} this way the ACP will be cached at the document model level and so you can use it 702 * for multiple permission checks without fetching it each time. 703 * 704 * @param docRef the doc ref to retrieve ACP or null if none 705 * @return the ACP 706 */ 707 ACP getACP(DocumentRef docRef); 708 709 /** 710 * Sets the ACP for this document. 711 * <p> 712 * If the ACP contains an <code>INHERITED</code> ACL it will be discarded. Only ACLs relative to the current 713 * document may be changed. 714 * <p> 715 * If the <code>overwrite</code> argument is false, the ACP is merged with the existing one if any. The merge is 716 * done as follow: 717 * <ul> 718 * <li>If any ACL is that already exists on the document ACp is redefined by the new ACO then it will be replaced by 719 * the new one. So if you want to remove an ACl in this mode you need to specify an empty ACL. 720 * <li>If the new ACP contains an ACl that is not defined by the old one the it will be added to the merged ACP. 721 * <li>If the <code>owners</code> are specified then they will replace the existing ones if any. Otherwise the old 722 * owners are preserved if any. As for the ACL if you want to remove existing owners you need to specify an empty 723 * owner array (and not a null one) 724 * </ul> 725 * If the <code>overwrite</code> argument is true, the old ACP will be replaced by the new one. 726 * <p> 727 * This way if you can remove the existing ACP by specifying a null ACP and <code>overwrite</code> argument set to 728 * true. 729 * <p> 730 * Setting a null ACP when <code>overwrite</code> is false will do nothing. 731 */ 732 void setACP(DocumentRef docRef, ACP acp, boolean overwrite); 733 734 /** 735 * Replace the {@code oldACE} with the {@code newACE} on the given {@code aclName}. 736 * <p> 737 * 738 * @since 7.4 739 */ 740 void replaceACE(DocumentRef docRef, String aclName, ACE oldACE, ACE newACE); 741 742 /** 743 * Returns {@code true} if negative ACLs are allowed. 744 * <p> 745 * Negative ACLs are ACLs that include an ACE with a deny (isGranted=false). This does not include the full-blocking 746 * ACE for Everyone/Everything, which is always allowed. 747 * 748 * @return {@code true} if negative ACLs are allowed 749 * @since 6.0 750 */ 751 boolean isNegativeAclAllowed(); 752 753 /* 754 * Support for lazy loading 755 */ 756 757 /** 758 * Retrieves a data model given a document reference and a schema. 759 * <p> 760 * For INTERNAL use by the core. 761 * 762 * @since 5.4.2 763 */ 764 DataModel getDataModel(DocumentRef docRef, Schema schema); 765 766 // -------- Versioning API --------------- 767 768 /** 769 * Gets the document corresponding to the last version for the given document. 770 * 771 * @param docRef the reference to the document 772 * @return the document model corresponding to the version 773 */ 774 DocumentModel getLastDocumentVersion(DocumentRef docRef); 775 776 /** 777 * Gets the document reference corresponding to the last version for the given document. 778 * 779 * @param docRef the reference to the document 780 * @return the document reference corresponding to the last version 781 */ 782 DocumentRef getLastDocumentVersionRef(DocumentRef docRef); 783 784 /** 785 * Gets the head (live) document for this document. 786 * 787 * @param docRef the reference to the document 788 * @return the version 789 */ 790 DocumentModel getSourceDocument(DocumentRef docRef); 791 792 /** 793 * Gets the references of the versions of the document. 794 * 795 * @param docRef the reference to the document 796 * @return a list of version references 797 * @since 1.4.1 798 */ 799 List<DocumentRef> getVersionsRefs(DocumentRef docRef); 800 801 /** 802 * Retrieves all the versions for a specified document. 803 * 804 * @param docRef the reference to the document 805 * @return the list of {@link DocumentModel} representing versions, empty list if none is found. 806 */ 807 List<DocumentModel> getVersions(DocumentRef docRef); 808 809 /** 810 * Retrieves all the versions for a specified document. 811 * 812 * @param docRef the reference to the document 813 * @return the list of {@link VersionModel} representing versions, empty list if none is found. 814 */ 815 List<VersionModel> getVersionsForDocument(DocumentRef docRef); 816 817 /** 818 * Gets a document version, given the versionable id and label. 819 * <p> 820 * The version model contains the label of the version to look for. On return, it is filled with the version's 821 * description and creation date. 822 * 823 * @param versionableId the versionable id 824 * @param versionModel the version model holding the label 825 * @return the version, or {@code null} if not found 826 */ 827 DocumentModel getVersion(String versionableId, VersionModel versionModel); 828 829 /** 830 * Gets the version label for a document, according to the versioning service. 831 * 832 * @param docModel the document 833 * @return the version label 834 */ 835 String getVersionLabel(DocumentModel docModel); 836 837 /** 838 * Returns a document that represents the specified version of the document. 839 * 840 * @param docRef the reference to the document 841 * @param version the version for which we want the corresponding document 842 */ 843 DocumentModel getDocumentWithVersion(DocumentRef docRef, VersionModel version); 844 845 /** 846 * Restores the given document to the specified version. 847 * 848 * @param docRef the reference to the document 849 * @param versionRef the reference to the version 850 * @param skipSnapshotCreation {@code true} if the document should not be snapshotted before being restored 851 * @param skipCheckout {@code true} if the restored document should be kept in a checked-in state 852 * @since 5.4 853 */ 854 DocumentModel restoreToVersion(DocumentRef docRef, DocumentRef versionRef, boolean skipSnapshotCreation, 855 boolean skipCheckout); 856 857 /** 858 * Restores the given document to the specified version. 859 * 860 * @param docRef the reference to the document 861 * @param versionRef the reference to the version 862 * @since 5.4 863 */ 864 DocumentModel restoreToVersion(DocumentRef docRef, DocumentRef versionRef); 865 866 /** 867 * Gets the version to which a checked in document is linked. 868 * <p> 869 * Returns {@code null} for a checked out document or a version or a proxy. 870 * 871 * @return the version, or {@code null} 872 */ 873 DocumentRef getBaseVersion(DocumentRef docRef); 874 875 /** 876 * Checks out a versioned document. 877 * 878 * @param docRef the reference to the document 879 */ 880 void checkOut(DocumentRef docRef); 881 882 /** 883 * Checks in a modified document, creating a new version. 884 * 885 * @param docRef the reference to the document 886 * @param option whether to do create a new {@link VersioningOption#MINOR} or {@link VersioningOption#MAJOR} version 887 * during check in 888 * @param checkinComment the checkin comment 889 * @return the version just created 890 * @since 5.4 891 */ 892 DocumentRef checkIn(DocumentRef docRef, VersioningOption option, String checkinComment); 893 894 /** 895 * Returns whether the current document is checked-out or not. 896 * 897 * @param docRef the reference to the document 898 */ 899 boolean isCheckedOut(DocumentRef docRef); 900 901 /** 902 * Gets the version series id for a document. 903 * <p> 904 * All documents and versions derived by a check in or checkout from the same original document share the same 905 * version series id. 906 * 907 * @param docRef the document reference 908 * @return the version series id 909 * @since 5.4 910 */ 911 String getVersionSeriesId(DocumentRef docRef); 912 913 /** 914 * Gets the working copy (live document) for a proxy or a version. 915 * 916 * @param docRef the document reference 917 * @return the working copy, or {@code null} if not found 918 * @since 5.4 919 */ 920 DocumentModel getWorkingCopy(DocumentRef docRef); 921 922 /** 923 * Creates a generic proxy to the given document inside the given folder. 924 * <p> 925 * The document may be a version, or a working copy (live document) in which case the proxy will be a "shortcut". 926 * 927 * @since 1.6.1 (5.3.1) 928 */ 929 DocumentModel createProxy(DocumentRef docRef, DocumentRef folderRef); 930 931 /** -------------------------- Query API --------------------------- * */ 932 933 /** 934 * Executes the given NXQL query an returns the result. 935 * 936 * @param query the query to execute 937 * @return the query result 938 */ 939 DocumentModelList query(String query); 940 941 /** 942 * Executes the given NXQL query an returns the result. 943 * 944 * @param query the query to execute 945 * @param max number of document to retrieve 946 * @return the query result 947 */ 948 DocumentModelList query(String query, int max); 949 950 /** 951 * Executes the given NXQL query and returns the result that matches the filter. 952 * 953 * @param query the query to execute 954 * @param filter the filter to apply to result 955 * @return the query result 956 */ 957 DocumentModelList query(String query, Filter filter); 958 959 /** 960 * Executes the given NXQL query and returns the result that matches the filter. 961 * 962 * @param query the query to execute 963 * @param filter the filter to apply to result 964 * @param max number of document to retrieve 965 * @return the query result 966 */ 967 DocumentModelList query(String query, Filter filter, int max); 968 969 /** 970 * Executes the given NXQL query and returns the result that matches the filter. 971 * 972 * @param query the query to execute 973 * @param filter the filter to apply to result 974 * @param limit the maximum number of documents to retrieve, or 0 for all of them 975 * @param offset the offset (starting at 0) into the list of documents 976 * @param countTotal if {@code true}, return a {@link DocumentModelList} that includes a total size of the 977 * underlying list (size if there was no limit or offset) 978 * @return the query result 979 */ 980 DocumentModelList query(String query, Filter filter, long limit, long offset, boolean countTotal); 981 982 /** 983 * Executes the given NXQL query and returns the result that matches the filter. 984 * 985 * @param query the query to execute 986 * @param filter the filter to apply to result 987 * @param limit the maximum number of documents to retrieve, or 0 for all of them 988 * @param offset the offset (starting at 0) into the list of documents 989 * @param countUpTo if {@code -1}, count the total size without offset/limit.<br> 990 * If {@code 0}, don't count the total size.<br> 991 * If {@code n}, count the total number if there are less than n documents otherwise set the size to 992 * {@code -1}. 993 * @return the query result 994 * @since 5.6 995 */ 996 DocumentModelList query(String query, Filter filter, long limit, long offset, long countUpTo); 997 998 /** 999 * Executes the given query and returns the result that matches the filter. 1000 * 1001 * @param query the query to execute 1002 * @param queryType the query type, like "NXQL" 1003 * @param filter the filter to apply to result 1004 * @param limit the maximum number of documents to retrieve, or 0 for all of them 1005 * @param offset the offset (starting at 0) into the list of documents 1006 * @param countTotal if {@code true}, return a {@link DocumentModelList} that includes a total size of the 1007 * underlying list (size if there was no limit or offset) 1008 * @return the query result 1009 * @since 5.5 1010 */ 1011 DocumentModelList query(String query, String queryType, Filter filter, long limit, long offset, boolean countTotal); 1012 1013 /** 1014 * Executes the given query and returns the result that matches the filter. 1015 * 1016 * @param query the query to execute 1017 * @param queryType the query type, like "NXQL" 1018 * @param filter the filter to apply to result 1019 * @param limit the maximum number of documents to retrieve, or 0 for all of them 1020 * @param offset the offset (starting at 0) into the list of documents 1021 * @param countUpTo if {@code -1}, return a {@link DocumentModelList} that includes a total size of the underlying 1022 * list (size if there was no limit or offset). <br> 1023 * If {@code 0}, don't return the total size of the underlying list. <br> 1024 * If {@code n}, return the total size of the underlying list when the size is smaller than {@code n} 1025 * else return a total size of {@code -1}. 1026 * @return the query result 1027 * @since 5.6 1028 */ 1029 DocumentModelList query(String query, String queryType, Filter filter, long limit, long offset, long countUpTo); 1030 1031 /** 1032 * Executes the given query and returns an iterable of maps containing the requested properties (which must be 1033 * closed when done). 1034 * 1035 * @param query the query to execute 1036 * @param queryType the query type, usually "NXQL" 1037 * @param params optional query-type-dependent parameters 1038 * @return an {@link IterableQueryResult}, which <b>must</b> be closed after use 1039 */ 1040 IterableQueryResult queryAndFetch(String query, String queryType, Object... params); 1041 1042 /** 1043 * Executes the given query and returns an iterable of maps containing the requested properties (which must be 1044 * closed when done). 1045 * <p> 1046 * It's possible to specify {@code distinctDocuments = true} to get a maximum of one row of results per document, 1047 * this will behave differently only when the {@code WHERE} clause contains wildcards. 1048 * 1049 * @param query the query to execute 1050 * @param queryType the query type, usually "NXQL" 1051 * @param distinctDocuments if {@code true} then a maximum of one row per document will be returned 1052 * @param params optional query-type-dependent parameters 1053 * @return an {@link IterableQueryResult}, which <b>must</b> be closed after use 1054 * @since 7.10-HF04, 8.2 1055 */ 1056 IterableQueryResult queryAndFetch(String query, String queryType, boolean distinctDocuments, Object... params); 1057 1058 /** 1059 * Executes the given query and returns the first batch of results, next batch must be requested within the 1060 * {@code keepAliveSeconds} delay. 1061 * 1062 * @param query The NXQL query to execute 1063 * @param batchSize The expected result batch size, note that more results can be returned when the backend don't 1064 * implement properly this feature 1065 * @param keepAliveSeconds The scroll context lifetime in seconds 1066 * @return A {@link ScrollResult} including the search results and a scroll id, to be passed to the subsequent calls 1067 * to {@link #scroll(String)} 1068 * @since 8.4 1069 */ 1070 ScrollResult scroll(String query, int batchSize, int keepAliveSeconds); 1071 1072 /** 1073 * Get the next batch of result, the {@code scrollId} is part of the previous {@link ScrollResult} response. 1074 * 1075 * @throws NuxeoException when the {@code scrollId} is unknown or when the scroll operation has timed out 1076 * @since 8.4 1077 */ 1078 ScrollResult scroll(String scrollId); 1079 1080 /** -------------------------- Security API --------------------------- * */ 1081 1082 /** 1083 * Retrieves the available security permissions existing in the system. 1084 * <p> 1085 * 1086 * @return a raw list of permission names, either basic or group names 1087 */ 1088 // TODO: (Hardcoded at the moment. In the future wil get data from 1089 // LDAP/database.) 1090 List<String> getAvailableSecurityPermissions(); 1091 1092 /** 1093 * Returns the life cycle of the document. 1094 * 1095 * @see org.nuxeo.ecm.core.lifecycle 1096 * @param docRef the document reference 1097 * @return the life cycle as a string 1098 */ 1099 String getCurrentLifeCycleState(DocumentRef docRef); 1100 1101 /** 1102 * Returns the life cycle policy of the document. 1103 * 1104 * @see org.nuxeo.ecm.core.lifecycle 1105 * @param docRef the document reference 1106 * @return the life cycle policy 1107 */ 1108 String getLifeCyclePolicy(DocumentRef docRef); 1109 1110 /** 1111 * Follows a given life cycle transition. 1112 * <p> 1113 * This will update the current life cycle of the document. 1114 * 1115 * @param docRef the document reference 1116 * @param transition the name of the transition to follow 1117 * @return a boolean representing the status if the operation 1118 * @throws LifeCycleException if the transition cannot be followed 1119 */ 1120 boolean followTransition(DocumentRef docRef, String transition) throws LifeCycleException; 1121 1122 /** 1123 * Follows a given life cycle transition. 1124 * <p> 1125 * This will update the current life cycle of the document. 1126 * 1127 * @param doc the document model 1128 * @param transition the name of the transition to follow 1129 * @return a boolean representing the status if the operation 1130 * @throws LifeCycleException if the transition cannot be followed 1131 */ 1132 boolean followTransition(DocumentModel doc, String transition) throws LifeCycleException; 1133 1134 /** 1135 * Gets the allowed state transitions for this document. 1136 * 1137 * @param docRef the document reference 1138 * @return a collection of state transitions as string 1139 */ 1140 Collection<String> getAllowedStateTransitions(DocumentRef docRef); 1141 1142 /** 1143 * Reinitializes the life cycle state of the document to its default state. 1144 * 1145 * @param docRef the document 1146 * @since 5.4.2 1147 */ 1148 void reinitLifeCycleState(DocumentRef docRef); 1149 1150 /** 1151 * Retrieves the given field value from the given schema for all the given documents. 1152 * 1153 * @param docRefs the document references 1154 * @param schema the schema 1155 * @param field the field name 1156 * @return the field values in the same order as the given docRefs 1157 */ 1158 Object[] getDataModelsField(DocumentRef[] docRefs, String schema, String field); 1159 1160 /** 1161 * Creates an array with all parent refs starting from the given document up to the root. So the return value will 1162 * have [0] = parent ref; [1] = parent parent ref... etc. 1163 * 1164 * @return an array with ancestor documents ref 1165 */ 1166 DocumentRef[] getParentDocumentRefs(DocumentRef docRef); 1167 1168 /** 1169 * Retrieves the given field value from the given schema for the given document along with all its parent documents. 1170 * 1171 * @param docRef the document reference 1172 * @param schema the schema 1173 * @param field the field name 1174 * @return an array with field values of all documents on the path from the given document to the root 1175 */ 1176 Object[] getDataModelsFieldUp(DocumentRef docRef, String schema, String field); 1177 1178 /** 1179 * Sets a lock on the given document. 1180 * 1181 * @param docRef the document reference 1182 * @return the lock info that was set 1183 * @throws LockException if the document is already locked 1184 * @since 5.4.2 1185 */ 1186 Lock setLock(DocumentRef docRef) throws LockException; 1187 1188 /** 1189 * Gets the lock info on the given document. 1190 * <p> 1191 * Lock info is never cached, and needs to use a separate transaction in a separate thread, so care should be taken 1192 * to not call this method needlessly. 1193 * 1194 * @param docRef the document reference 1195 * @return the lock info if the document is locked, or {@code null} otherwise 1196 * @since 5.4.2 1197 */ 1198 Lock getLockInfo(DocumentRef docRef); 1199 1200 /** 1201 * Removes the lock on the given document. 1202 * <p> 1203 * The caller principal should be the same as the one who set the lock or to belongs to the administrator group, 1204 * otherwise an exception will be throw. 1205 * <p> 1206 * If the document was not locked, does nothing. 1207 * <p> 1208 * Returns the previous lock info. 1209 * 1210 * @param docRef the document to unlock 1211 * @return the removed lock info, or {@code null} if there was no lock 1212 * @since 5.4.2 1213 * @throws LockException if the document is locked by someone else 1214 */ 1215 Lock removeLock(DocumentRef docRef) throws LockException; 1216 1217 /** 1218 * Applies default Read permissions on root JCR Document for the given user or group name. It can only be called by 1219 * Administrators. 1220 * <p> 1221 * Usage: As an administrator, you may want to add new users or groups. This method needs to be called to grand 1222 * default reading permissions on the root document of the repository for the newly created users/groups. 1223 */ 1224 void applyDefaultPermissions(String userOrGroupName); 1225 1226 /** 1227 * Publishes the document in a section overwriting any existing proxy to the same document. This is simmilar to 1228 * publishDocument(docToPublish, section, true); 1229 * 1230 * @return The proxy document that was created 1231 * @since 1.4.1 for the case where docToPublish is a proxy 1232 */ 1233 DocumentModel publishDocument(DocumentModel docToPublish, DocumentModel section); 1234 1235 /** 1236 * Publishes the document in a section. 1237 * 1238 * @return The proxy document that was created 1239 */ 1240 DocumentModel publishDocument(DocumentModel docToPublish, DocumentModel section, boolean overwriteExistingProxy); 1241 1242 /** 1243 * Finds the proxies for a document. If the parent is not null, the search will be limited to its direct children. 1244 * <p> 1245 * If the document is a version, then only proxies to that version will be looked up. 1246 * <p> 1247 * If the document is a proxy, then all similar proxies (pointing to any version of the same versionable) are 1248 * retrieved. 1249 * 1250 * @param docRef the target document for the proxies 1251 * @param folderRef the folder where proxies are located or {@code null} 1252 * @return the list of the proxies. An empty list is returned if no proxy are found 1253 * @since 1.4.1 for the case where docRef is a proxy 1254 */ 1255 DocumentModelList getProxies(DocumentRef docRef, DocumentRef folderRef); 1256 1257 /** 1258 * Returns the type of his parent SuperSpace (workspace, section, etc.). SuperSpace is qualified by the SuperSpace 1259 * facet. 1260 */ 1261 String getSuperParentType(DocumentModel doc); 1262 1263 /** 1264 * Returns the parent SuperSpace (workspace, section, etc.). SuperSpace is qualified by the SuperSpace facet. 1265 * 1266 * @return DocumentModel of SuperSpace 1267 */ 1268 DocumentModel getSuperSpace(DocumentModel doc); 1269 1270 /** 1271 * Returns the repository name against which this core session is bound. 1272 * 1273 * @return the repository name used currently used as an identifier 1274 */ 1275 String getRepositoryName(); 1276 1277 /** 1278 * Gets system property of the specified type for the document ref. 1279 */ 1280 <T extends Serializable> T getDocumentSystemProp(DocumentRef ref, String systemProperty, Class<T> type); 1281 1282 /** 1283 * Sets given value as a system property. 1284 */ 1285 <T extends Serializable> void setDocumentSystemProp(DocumentRef ref, String systemProperty, T value); 1286 1287 /** 1288 * Given a parent document, order the source child before the destination child. The source and destination must be 1289 * name of child documents of the given parent document. (a document name can be retrieved using 1290 * <code>docModel.getName()</code>) To place the source document at the end of the children list use a null 1291 * destination node. 1292 * 1293 * @param parent the parent document 1294 * @param src the document to be moved (ordered) 1295 * @param dest the document before which the reordered document will be placed If null the source document will be 1296 * placed at the end of the children list 1297 */ 1298 void orderBefore(DocumentRef parent, String src, String dest); 1299 1300 /** 1301 * Internal method - it is used internally by {@link DocumentModel#refresh()} 1302 * <p> 1303 * Get fresh data from a document given a description of what kind of data should be refetched. 1304 * <p> 1305 * The refresh information is specified using a bit mask. See {@link DocumentModel} for all accepted flags. 1306 * <p> 1307 * When the flag {@link DocumentModel#REFRESH_CONTENT_IF_LOADED} is specified a third argument must be passed 1308 * representing the schema names for document parts to refresh. This argument is ignored if the flag is not 1309 * specified or no schema names are provided 1310 * 1311 * @param ref the document reference 1312 * @param refreshFlags refresh flags as defined in {@link DocumentModel} 1313 * @param schemas the schema names if a partial content refresh is required 1314 * @return a DocumentModelRefresh object 1315 */ 1316 DocumentModelRefresh refreshDocument(DocumentRef ref, int refreshFlags, String[] schemas); 1317 1318 /** 1319 * Provides the full list of all permissions or groups of permissions that contain the given one (inclusive). It 1320 * makes the method {@link org.nuxeo.ecm.core.security.SecurityService#getPermissionsToCheck} available remote. 1321 * 1322 * @return the list, as an array of strings. 1323 */ 1324 String[] getPermissionsToCheck(String permission); 1325 1326 /** 1327 * Find the first parent with the given {@code facet} and adapt it on the {@code adapterClass}. 1328 * <p> 1329 * This method does not check the permissions on the document to be adapted of this {@code CoreSession}'s 1330 * {@code Principal}, and so the adapter must not need other schemas from the {@code DocumentModel} except the 1331 * schemas related to the given facet. 1332 * 1333 * @return the first parent with the given {@code facet} adapted, or {@code null} if no parent found or the document 1334 * does not support the given {@code adapterClass}. 1335 * @since 5.4.2 1336 */ 1337 <T extends DetachedAdapter> T adaptFirstMatchingDocumentWithFacet(DocumentRef docRef, String facet, 1338 Class<T> adapterClass); 1339 1340 /** 1341 * Gets the fulltext extracted from the binary fields. We defined a new API for that to avoid to store in the cache 1342 * the fulltext properties which could be huge. This method handle if document is a proxy or not. Historically, VCS 1343 * doesn't store fulltext properties for proxies (note that DBS does). 1344 * 1345 * @param ref the document reference 1346 * @return the fulltext map or {@code null} if not supported. 1347 * @since 5.9.3 1348 */ 1349 Map<String, String> getBinaryFulltext(DocumentRef ref); 1350 1351 /** @since 8.2 */ 1352 enum CopyOption { 1353 1354 RESET_LIFE_CYCLE, 1355 1356 RESET_CREATOR; 1357 1358 public static boolean isResetLifeCycle(CopyOption... options) { 1359 return Arrays.asList(options).contains(RESET_LIFE_CYCLE); 1360 } 1361 1362 public static boolean isResetCreator(CopyOption... options) { 1363 return Arrays.asList(options).contains(RESET_CREATOR); 1364 } 1365 1366 } 1367 1368 /** 1369 * Gets the current change token for the document. 1370 * <p> 1371 * The change token is an opaque string which is modified every time the document is changed. 1372 * <p> 1373 * Before saving a document through {@link CoreSession#saveDocument} it's possible to pass an expected change token 1374 * in the document context data through {@code doc.putContextData(CoreSession.CHANGE_TOKEN, expectedChangeToken)}. 1375 * If the change token does not match the stored one, it means that a concurrent update happened, and a 1376 * {@link org.nuxeo.ecm.core.api.ConcurrentUpdateException ConcurrentUpdateException} will be thrown. 1377 * 1378 * @param ref the document reference 1379 * @return the change token 1380 * @since 9.1 1381 * @see DocumentModel#putContextData 1382 * @see #CHANGE_TOKEN 1383 * @see #getChangeToken 1384 */ 1385 String getChangeToken(DocumentRef ref); 1386 1387}