001/* 002 * (C) Copyright 2006-2019 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 * Julien Anguenot 019 * Florent Guillaume 020 */ 021package org.nuxeo.ecm.core.model; 022 023import java.io.Serializable; 024import java.util.Calendar; 025import java.util.Collection; 026import java.util.List; 027import java.util.Map; 028import java.util.Set; 029import java.util.function.Consumer; 030 031import org.nuxeo.ecm.core.api.Blob; 032import org.nuxeo.ecm.core.api.CoreSession; 033import org.nuxeo.ecm.core.api.DocumentNotFoundException; 034import org.nuxeo.ecm.core.api.LifeCycleException; 035import org.nuxeo.ecm.core.api.Lock; 036import org.nuxeo.ecm.core.api.NuxeoPrincipal; 037import org.nuxeo.ecm.core.api.PropertyException; 038import org.nuxeo.ecm.core.api.model.DocumentPart; 039import org.nuxeo.ecm.core.schema.DocumentType; 040 041/** 042 * A low-level document from a {@link Session}. 043 */ 044public interface Document { 045 046 /** 047 * Gets the session that owns this document. 048 * 049 * @return the session 050 */ 051 Session getSession(); 052 053 /** 054 * Gets the name of this document. 055 * 056 * @return the document name 057 */ 058 String getName(); 059 060 /** 061 * Gets the document's position in its containing folder (if ordered). 062 * 063 * @return the position 064 * @since 6.0 065 */ 066 Long getPos(); 067 068 /** 069 * Gets this document's UUID. 070 * 071 * @return the document UUID 072 */ 073 String getUUID(); 074 075 /** 076 * Gets the parent document, or {@code null} if this is the root document. 077 * 078 * @return the parent document, or {@code null} 079 */ 080 Document getParent(); 081 082 /** 083 * Gets the type of this document. 084 * 085 * @return the document type 086 */ 087 DocumentType getType(); 088 089 /** 090 * Gets the path of this document. 091 * 092 * @return the path 093 */ 094 String getPath(); 095 096 /** 097 * Sets a simple property value. 098 * <p> 099 * For more generic properties described by an xpath, use {@link #setValue} instead. 100 * 101 * @param name the name of the property to set 102 * @param value the value to set 103 * @see #setValue 104 */ 105 void setPropertyValue(String name, Serializable value); 106 107 /** 108 * Sets a property value. 109 * <p> 110 * The xpath may point to a partial path, in which case the value may be a complex {@link List} or {@link Map}. 111 * 112 * @param xpath the xpath of the property to set 113 * @param value the value to set 114 * @throws PropertyException if the property does not exist or the value is of the wrong type 115 * @since 7.3 116 */ 117 void setValue(String xpath, Object value) throws PropertyException; 118 119 /** 120 * Gets a simple property value. 121 * <p> 122 * For more generic properties described by an xpath, use {@link #getValue} instead. 123 * 124 * @param name the name of the property to get 125 * @return the property value or {@code null} if the property is not set 126 * @see #getValue 127 */ 128 Serializable getPropertyValue(String name); 129 130 /** 131 * Gets a property value. 132 * <p> 133 * The xpath may point to a partial path, in which case the value may be a complex {@link List} or {@link Map}. 134 * 135 * @param xpath the xpath of the property to set 136 * @return the property value or {@code null} if the property is not set 137 * @throws PropertyException if the property does not exist 138 */ 139 Object getValue(String xpath) throws PropertyException; 140 141 /** 142 * An accessor that can read or write a blob and know its xpath. 143 * 144 * @since 7.3 145 */ 146 interface BlobAccessor { 147 /** Gets the blob's xpath. */ 148 String getXPath(); 149 150 /** Gets the blob. */ 151 Blob getBlob(); 152 153 /** Sets the blob. */ 154 void setBlob(Blob blob); 155 } 156 157 /** 158 * Visits all the blobs of this document and calls the passed blob visitor on each one. 159 * 160 * @since 7.3 161 */ 162 void visitBlobs(Consumer<BlobAccessor> blobVisitor) throws PropertyException; 163 164 /** 165 * Checks whether this document is a folder. 166 * 167 * @return {@code true} if the document is a folder, {@code false} otherwise 168 */ 169 boolean isFolder(); 170 171 /** 172 * Sets this document as readonly or not. 173 * 174 * @since 5.9.2 175 */ 176 void setReadOnly(boolean readonly); 177 178 /** 179 * Checks whether this document is readonly or not. 180 * 181 * @since 5.9.2 182 */ 183 boolean isReadOnly(); 184 185 /** 186 * Removes this document and all its children, if any. 187 */ 188 void remove(); 189 190 /** 191 * Removes this document and all its children, if any. 192 * 193 * @param principal the caller 194 * @since 11.1 195 */ 196 void remove(NuxeoPrincipal principal); 197 198 /** 199 * Removes this document only, without its children. 200 * 201 * @since 11.1 202 */ 203 void removeSingleton(); 204 205 /** 206 * Turns the document into a record. 207 * <p> 208 * A record is a document with specific capabilities related to mandatory retention until a given date, and legal 209 * holds. In addition, its main blob receives special treatment from the document blob manager to make sure it's 210 * never shared with another blob at the storage level, and is deleted as soon as the record is deleted. 211 * <p> 212 * If the document is already a record, this method has no effect. 213 * <p> 214 * The permission {@value org.nuxeo.ecm.core.api.security.SecurityConstants#MAKE_RECORD} is required. 215 * 216 * @see #isRecord 217 * @since 11.1 218 */ 219 void makeRecord(); 220 221 /** 222 * Checks if the document is a record. 223 * 224 * @return {@code true} if the document is a record, {@code false} otherwise 225 * @see #makeRecord 226 * @since 11.1 227 */ 228 boolean isRecord(); 229 230 /** 231 * Sets a retention date for the document (a record). 232 * <p> 233 * If no previous retention date was set, or if the previous retention date was 234 * {@linkplain CoreSession#RETAIN_UNTIL_INDETERMINATE indeterminate}, or if the previous retention date was 235 * <em>before</em> the given value, then the retention date is set to the given value. 236 * <p> 237 * If the previous retention date was <em>after</em> the given value (that is, if trying to reduce the retention 238 * time), an exception is thrown. 239 * <p> 240 * If the given value is {@code null} and the previous retention date is in the past (it has already expired), then 241 * the retention date is set to {@code null}. 242 * <p> 243 * The permission {@value org.nuxeo.ecm.core.api.security.SecurityConstants#SET_RETENTION} is required. 244 * 245 * @param retainUntil the new retention date 246 * @throws PropertyException if trying to reduce the retention time, or if the document is not a record 247 * @see #getRetainUntil 248 * @see CoreSession#RETAIN_UNTIL_INDETERMINATE 249 * @since 11.1 250 */ 251 void setRetainUntil(Calendar retainUntil) throws PropertyException; 252 253 /** 254 * Gets the retention date for the document. 255 * 256 * @return the retention date, or {@value org.nuxeo.ecm.core.api.security.SecurityConstants#SET_RETENTION} for a 257 * retention in the indeterminate future, or {@code null} if there is no retention date 258 * @see #setRetainUntil 259 * @see CoreSession#RETAIN_UNTIL_INDETERMINATE 260 * @since 11.1 261 */ 262 Calendar getRetainUntil(); 263 264 /** 265 * Sets or removes a legal hold on the document (a record). 266 * <p> 267 * The permission {@value org.nuxeo.ecm.core.api.security.SecurityConstants#MANAGE_LEGAL_HOLD} is required. 268 * 269 * @param hold {@code true} to set a legal hold, {@code false} to remove it 270 * @see #hasLegalHold 271 * @throws PropertyException if the document is not a record 272 * @since 11.1 273 */ 274 void setLegalHold(boolean hold); 275 276 /** 277 * Checks if the document has a legal hold set. 278 * 279 * @return {@code true} if a legal hold has been set on the document, {@code false} otherwise 280 * @see #setLegalHold 281 * @since 11.1 282 */ 283 boolean hasLegalHold(); 284 285 /** 286 * Checks if the document has a retention date in the future or has a legal hold. 287 * 288 * @return {@code true} if the document has a retention date in the future or if it has a legal hold, {@code false} 289 * otherwise 290 * @see #getRetainUntil 291 * @see #hasLegalHold 292 * @since 11.1 293 */ 294 boolean isUnderRetentionOrLegalHold(); 295 296 /** 297 * Checks whether this document is under active retention. 298 * 299 * @since 9.3 300 * @deprecated since 11.1, unused, use {@link #hasLegalHold} instead 301 */ 302 @Deprecated 303 boolean isRetentionActive(); 304 305 /** 306 * Sets or unsets this document as under active retention. 307 * 308 * @since 9.3 309 * @deprecated since 11.1, unused, use {@link #setLegalHold} instead 310 */ 311 @Deprecated 312 void setRetentionActive(boolean retentionActive); 313 314 /** 315 * Gets the life cycle state of this document. 316 * 317 * @return the life cycle state 318 */ 319 String getLifeCycleState(); 320 321 /** 322 * Sets the life cycle state of this document. 323 * 324 * @param state the life cycle state 325 */ 326 void setCurrentLifeCycleState(String state); 327 328 /** 329 * Gets the life cycle policy of this document. 330 * 331 * @return the life cycle policy 332 */ 333 String getLifeCyclePolicy(); 334 335 /** 336 * Sets the life cycle policy of this document. 337 * 338 * @param policy the life cycle policy 339 */ 340 void setLifeCyclePolicy(String policy); 341 342 /** 343 * Follows a given life cycle transition. 344 * <p> 345 * This will update the life cycle state of the document. 346 * 347 * @param transition the name of the transition to follow 348 */ 349 void followTransition(String transition) throws LifeCycleException; 350 351 /** 352 * Returns the allowed state transitions for this document. 353 * 354 * @return a collection of state transitions 355 */ 356 Collection<String> getAllowedStateTransitions(); 357 358 /** 359 * Checks whether or not this document is a proxy. 360 * 361 * @return {@code true} if this document is a proxy, {@code false} otherwise 362 */ 363 boolean isProxy(); 364 365 /** 366 * Gets the repository in which the document lives. 367 * 368 * @return the repository name. 369 */ 370 String getRepositoryName(); 371 372 /** 373 * Sets a system property. 374 */ 375 void setSystemProp(String name, Serializable value); 376 377 /** 378 * Gets a system property. 379 */ 380 <T extends Serializable> T getSystemProp(String name, Class<T> type); 381 382 /** 383 * Gets the current change token for this document. 384 * 385 * @return the change token 386 * @since 9.1 387 */ 388 String getChangeToken(); 389 390 /** 391 * Validates that the passed user-visible change token is compatible with the one for this document. 392 * 393 * @return {@code false} if the change token is not valid 394 * @since 9.2 395 */ 396 boolean validateUserVisibleChangeToken(String changeToken); 397 398 /** 399 * Marks the document as being modified by a user change. 400 * <p> 401 * This causes an additional change token increment and check during save. 402 * 403 * @since 9.2 404 */ 405 void markUserChange(); 406 407 /** 408 * Loads a {@link DocumentPart} from storage. 409 * <p> 410 * Reading data is done by {@link DocumentPart} because of per-proxy schemas. 411 */ 412 void readDocumentPart(DocumentPart dp) throws PropertyException; 413 414 /** 415 * Context passed to write operations to optionally record things to do at {@link #flush} time. 416 * 417 * @since 7.3 418 */ 419 interface WriteContext { 420 /** 421 * Gets the recorded changed xpaths. 422 */ 423 Set<String> getChanges(); 424 425 /** 426 * Flushes recorded write operations. 427 * 428 * @param doc the base document being written 429 */ 430 void flush(Document doc); 431 } 432 433 /** 434 * Gets a write context for the current document. 435 * 436 * @since 7.3 437 */ 438 WriteContext getWriteContext(); 439 440 /** 441 * Writes a {@link DocumentPart} to storage. 442 * <p> 443 * Writing data is done by {@link DocumentPart} because of per-proxy schemas. 444 * 445 * @param dp the document part 446 * @param writeContext the write context 447 * @param create whether this is for a document creation 448 * @return {@code true} if something changed 449 * @since 11.1 450 */ 451 boolean writeDocumentPart(DocumentPart dp, WriteContext writeContext, boolean create) throws PropertyException; 452 453 /** 454 * Writes a {@link DocumentPart} to storage. 455 * <p> 456 * Writing data is done by {@link DocumentPart} because of per-proxy schemas. 457 * 458 * @return {@code true} if something changed 459 * @deprecated since 11.1, use the signature with {@code create} instead 460 */ 461 @Deprecated 462 default boolean writeDocumentPart(DocumentPart dp, WriteContext writeContext) throws PropertyException { 463 return writeDocumentPart(dp, writeContext, false); 464 } 465 466 /** 467 * Gets the facets available on this document (from the type and the instance facets). 468 * 469 * @return the facets 470 * @since 5.4.2 471 */ 472 Set<String> getAllFacets(); 473 474 /** 475 * Gets the facets defined on this document instance. The type facets are not returned. 476 * 477 * @return the facets 478 * @since 5.4.2 479 */ 480 String[] getFacets(); 481 482 /** 483 * Checks whether this document has a given facet, either from its type or added on the instance. 484 * 485 * @param facet the facet name 486 * @return {@code true} if the document has the facet 487 * @since 5.4.2 488 */ 489 boolean hasFacet(String facet); 490 491 /** 492 * Adds a facet to this document. 493 * <p> 494 * Does nothing if the facet was already present on the document. 495 * 496 * @param facet the facet name 497 * @return {@code true} if the facet was added, or {@code false} if it is already present 498 * @throws IllegalArgumentException if the facet does not exist 499 * @since 5.4.2 500 */ 501 boolean addFacet(String facet); 502 503 /** 504 * Removes a facet from this document. 505 * <p> 506 * It's not possible to remove a facet coming from the document type. 507 * 508 * @param facet the facet name 509 * @return {@code true} if the facet was removed, or {@code false} if it isn't present or is present on the type or 510 * does not exit 511 * @since 5.4.2 512 */ 513 boolean removeFacet(String facet); 514 515 /** 516 * Sets a lock on this document. 517 * 518 * @param lock the lock to set 519 * @return {@code null} if locking succeeded, or the existing lock if locking failed 520 */ 521 Lock setLock(Lock lock); 522 523 /** 524 * Removes a lock from this document. 525 * 526 * @param owner the owner to check, or {@code null} for no check 527 * @return {@code null} if there was no lock or if removal succeeded, or a lock if it blocks removal due to owner 528 * mismatch 529 */ 530 Lock removeLock(String owner); 531 532 /** 533 * Gets the lock if one set on this document. 534 * 535 * @return the lock, or {@code null} if no lock is set 536 */ 537 Lock getLock(); 538 539 /** 540 * Gets a child document given its name. 541 * <p> 542 * Throws {@link DocumentNotFoundException} if the document could not be found. 543 * 544 * @param name the name of the child to retrieve 545 * @return the child if exists 546 * @throws DocumentNotFoundException if the child does not exist 547 */ 548 Document getChild(String name); 549 550 /** 551 * Gets the children of the document. 552 * 553 * @return the children 554 */ 555 List<Document> getChildren(); 556 557 /** 558 * Gets a list of the children ids. 559 * 560 * @return a list of children ids. 561 * @since 1.4.1 562 */ 563 List<String> getChildrenIds(); 564 565 /** 566 * Checks whether this document has a child of the given name. 567 * 568 * @param name the name of the child to check 569 * @return {@code true} if the child exists, {@code false} otherwise 570 */ 571 boolean hasChild(String name); 572 573 /** 574 * Tests if the document has any children. 575 * 576 * @return {@code true} if the document has children, {@code false} otherwise 577 */ 578 boolean hasChildren(); 579 580 /** 581 * Creates a new child document of the given type. 582 * 583 * @param name the name of the new child to create 584 * @param typeName the type of the child to create 585 * @return the newly created document 586 */ 587 Document addChild(String name, String typeName); 588 589 /** 590 * Orders the given source child before the destination child. 591 * <p> 592 * Both source and destination must be names that point to child documents of this document. The source document 593 * will be placed before the destination one. If destination is {@code null}, the source document will be appended 594 * at the end of the children list. 595 * 596 * @param src the document to move 597 * @param dest the document before which to place the source document 598 */ 599 void orderBefore(String src, String dest); 600 601 /** 602 * Creates a new version. 603 * 604 * @param label the version label 605 * @param checkinComment the checkin comment 606 * @return the created version 607 */ 608 Document checkIn(String label, String checkinComment); 609 610 void checkOut(); 611 612 /** 613 * Gets the list of version ids for this document. 614 * 615 * @return the list of version ids 616 * @since 1.4.1 617 */ 618 List<String> getVersionsIds(); 619 620 /** 621 * Gets the versions for this document. 622 * 623 * @return the versions of the document, or an empty list if there are no versions 624 */ 625 List<Document> getVersions(); 626 627 /** 628 * Gets the last version of this document. 629 * <p> 630 * Returns {@code null} if there is no version at all. 631 * 632 * @return the last version, or {@code null} if there is no version 633 */ 634 Document getLastVersion(); 635 636 /** 637 * Gets the source for this document. 638 * <p> 639 * For a version, it's the working copy. 640 * <p> 641 * For a proxy, it's the version the proxy points to. 642 * 643 * @return the source document 644 */ 645 Document getSourceDocument(); 646 647 /** 648 * Replaces this document's content with the version specified. 649 * 650 * @param version the version to replace with 651 */ 652 void restore(Document version); 653 654 /** 655 * Gets a version of this document, given its label. 656 * 657 * @param label the version label 658 * @return the version 659 */ 660 Document getVersion(String label); 661 662 /** 663 * Checks whether this document is a version document. 664 * 665 * @return {@code true} if it's a version, {@code false} otherwise 666 */ 667 boolean isVersion(); 668 669 /** 670 * Gets the version to which a checked in document is linked. 671 * <p> 672 * Returns {@code null} for a checked out document or a version or a proxy. 673 * 674 * @return the version, or {@code null} 675 */ 676 Document getBaseVersion(); 677 678 /** 679 * Checks whether this document is checked out. 680 * 681 * @return {@code true} if the document is checked out, or {@code false} otherwise 682 */ 683 boolean isCheckedOut(); 684 685 /** 686 * Gets the version creation date of this document if it's a version or a proxy. 687 * 688 * @return the version creation date, or {@code null} if it's not a version or a proxy 689 */ 690 Calendar getVersionCreationDate(); 691 692 /** 693 * Gets the version check in comment of this document if it's a version or a proxy. 694 * 695 * @return the check in comment, or {@code null} if it's not a version or a proxy 696 */ 697 String getCheckinComment(); 698 699 /** 700 * Gets the version series id. 701 * 702 * @return the version series id 703 */ 704 String getVersionSeriesId(); 705 706 /** 707 * Gets the version label. 708 * 709 * @return the version label 710 */ 711 String getVersionLabel(); 712 713 /** 714 * Checks whether this document is the latest version. 715 * 716 * @return {@code true} if this is the latest version, or {@code false} otherwise 717 */ 718 boolean isLatestVersion(); 719 720 /** 721 * Checks whether this document is a major version. 722 * 723 * @return {@code true} if this is a major version, or {@code false} otherwise 724 */ 725 boolean isMajorVersion(); 726 727 /** 728 * Checks whether this document is the latest major version. 729 * 730 * @return {@code true} if this is the latest major version, or {@code false} otherwise 731 */ 732 boolean isLatestMajorVersion(); 733 734 /** 735 * Checks if there is a checked out working copy for the version series of this document. 736 * 737 * @return {@code true} if there is a checked out working copy 738 */ 739 boolean isVersionSeriesCheckedOut(); 740 741 /** 742 * Gets the working copy for this document. 743 * 744 * @return the working copy 745 */ 746 Document getWorkingCopy(); 747 748 /** 749 * Gets the document (version or live document) to which this proxy points. 750 */ 751 Document getTargetDocument(); 752 753 /** 754 * Sets the document (version or live document) to which this proxy points. 755 */ 756 void setTargetDocument(Document target); 757 758}