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}