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