001/*
002 * (C) Copyright 2006-2014 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     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.DocumentNotFoundException;
033import org.nuxeo.ecm.core.api.LifeCycleException;
034import org.nuxeo.ecm.core.api.Lock;
035import org.nuxeo.ecm.core.api.PropertyException;
036import org.nuxeo.ecm.core.api.model.DocumentPart;
037import org.nuxeo.ecm.core.schema.DocumentType;
038
039/**
040 * A low-level document from a {@link Session}.
041 */
042public interface Document {
043
044    /**
045     * Gets the session that owns this document.
046     *
047     * @return the session
048     */
049    Session getSession();
050
051    /**
052     * Gets the name of this document.
053     *
054     * @return the document name
055     */
056    String getName();
057
058    /**
059     * Gets the document's position in its containing folder (if ordered).
060     *
061     * @return the position
062     * @since 6.0
063     */
064    Long getPos();
065
066    /**
067     * Gets this document's UUID.
068     *
069     * @return the document UUID
070     */
071    String getUUID();
072
073    /**
074     * Gets the parent document, or {@code null} if this is the root document.
075     *
076     * @return the parent document, or {@code null}
077     */
078    Document getParent();
079
080    /**
081     * Gets the type of this document.
082     *
083     * @return the document type
084     */
085    DocumentType getType();
086
087    /**
088     * Gets the path of this document.
089     *
090     * @return the path
091     */
092    String getPath();
093
094    /**
095     * Sets a simple property value.
096     * <p>
097     * For more generic properties described by an xpath, use {@link #setValue} instead.
098     *
099     * @param name the name of the property to set
100     * @param value the value to set
101     * @see #setValue
102     */
103    void setPropertyValue(String name, Serializable value);
104
105    /**
106     * Sets a property value.
107     * <p>
108     * The xpath may point to a partial path, in which case the value may be a complex {@link List} or {@link Map}.
109     *
110     * @param xpath the xpath of the property to set
111     * @param value the value to set
112     * @throws PropertyException if the property does not exist or the value is of the wrong type
113     * @since 7.3
114     */
115    void setValue(String xpath, Object value) throws PropertyException;
116
117    /**
118     * Gets a simple property value.
119     * <p>
120     * For more generic properties described by an xpath, use {@link #getValue} instead.
121     *
122     * @param name the name of the property to get
123     * @return the property value or {@code null} if the property is not set
124     * @see #getValue
125     */
126    Serializable getPropertyValue(String name);
127
128    /**
129     * Gets a property value.
130     * <p>
131     * The xpath may point to a partial path, in which case the value may be a complex {@link List} or {@link Map}.
132     *
133     * @param xpath the xpath of the property to set
134     * @return the property value or {@code null} if the property is not set
135     * @throws PropertyException if the property does not exist
136     */
137    Object getValue(String xpath) throws PropertyException;
138
139    /**
140     * An accessor that can read or write a blob and know its xpath.
141     *
142     * @since 7.3
143     */
144    interface BlobAccessor {
145        /** Gets the blob's xpath. */
146        String getXPath();
147
148        /** Gets the blob. */
149        Blob getBlob();
150
151        /** Sets the blob. */
152        void setBlob(Blob blob);
153    }
154
155    /**
156     * Visits all the blobs of this document and calls the passed blob visitor on each one.
157     *
158     * @since 7.3
159     */
160    void visitBlobs(Consumer<BlobAccessor> blobVisitor) throws PropertyException;
161
162    /**
163     * Checks whether this document is a folder.
164     *
165     * @return {@code true} if the document is a folder, {@code false} otherwise
166     */
167    boolean isFolder();
168
169    /**
170     * Sets this document as readonly or not.
171     *
172     * @since 5.9.2
173     */
174    void setReadOnly(boolean readonly);
175
176    /**
177     * Checks whether this document is readonly or not.
178     *
179     * @since 5.9.2
180     */
181    boolean isReadOnly();
182
183    /**
184     * Removes this document and all its children, if any.
185     */
186    void remove();
187
188    /**
189     * Checks whether this document is under active retention.
190     *
191     * @since 9.3
192     */
193    boolean isRetentionActive();
194
195    /**
196     * Sets or unsets this document as under active retention.
197     *
198     * @since 9.3
199     */
200    void setRetentionActive(boolean retentionActive);
201
202    /**
203     * Gets the life cycle state of this document.
204     *
205     * @return the life cycle state
206     */
207    String getLifeCycleState();
208
209    /**
210     * Sets the life cycle state of this document.
211     *
212     * @param state the life cycle state
213     */
214    void setCurrentLifeCycleState(String state);
215
216    /**
217     * Gets the life cycle policy of this document.
218     *
219     * @return the life cycle policy
220     */
221    String getLifeCyclePolicy();
222
223    /**
224     * Sets the life cycle policy of this document.
225     *
226     * @param policy the life cycle policy
227     */
228    void setLifeCyclePolicy(String policy);
229
230    /**
231     * Follows a given life cycle transition.
232     * <p>
233     * This will update the life cycle state of the document.
234     *
235     * @param transition the name of the transition to follow
236     */
237    void followTransition(String transition) throws LifeCycleException;
238
239    /**
240     * Returns the allowed state transitions for this document.
241     *
242     * @return a collection of state transitions
243     */
244    Collection<String> getAllowedStateTransitions();
245
246    /**
247     * Checks whether or not this document is a proxy.
248     *
249     * @return {@code true} if this document is a proxy, {@code false} otherwise
250     */
251    boolean isProxy();
252
253    /**
254     * Gets the repository in which the document lives.
255     *
256     * @return the repository name.
257     */
258    String getRepositoryName();
259
260    /**
261     * Sets a system property.
262     */
263    void setSystemProp(String name, Serializable value);
264
265    /**
266     * Gets a system property.
267     */
268    <T extends Serializable> T getSystemProp(String name, Class<T> type);
269
270    /**
271     * Gets the current change token for this document.
272     *
273     * @return the change token
274     * @since 9.1
275     */
276    String getChangeToken();
277
278    /**
279     * Validates that the passed user-visible change token is compatible with the one for this document.
280     *
281     * @return {@code false} if the change token is not valid
282     * @since 9.2
283     */
284    boolean validateUserVisibleChangeToken(String changeToken);
285
286    /**
287     * Marks the document as being modified by a user change.
288     * <p>
289     * This causes an additional change token increment and check during save.
290     *
291     * @since 9.2
292     */
293    void markUserChange();
294
295    /**
296     * Loads a {@link DocumentPart} from storage.
297     * <p>
298     * Reading data is done by {@link DocumentPart} because of per-proxy schemas.
299     */
300    void readDocumentPart(DocumentPart dp) throws PropertyException;
301
302    /**
303     * Context passed to write operations to optionally record things to do at {@link #flush} time.
304     *
305     * @since 7.3
306     */
307    interface WriteContext {
308        /**
309         * Gets the recorded changed xpaths.
310         */
311        Set<String> getChanges();
312
313        /**
314         * Flushes recorded write operations.
315         *
316         * @param doc the base document being written
317         */
318        void flush(Document doc);
319    }
320
321    /**
322     * Gets a write context for the current document.
323     *
324     * @since 7.3
325     */
326    WriteContext getWriteContext();
327
328    /**
329     * Writes a {@link DocumentPart} to storage.
330     * <p>
331     * Writing data is done by {@link DocumentPart} because of per-proxy schemas.
332     *
333     * @return {@code true} if something changed
334     */
335    boolean writeDocumentPart(DocumentPart dp, WriteContext writeContext) throws PropertyException;
336
337    /**
338     * Gets the facets available on this document (from the type and the instance facets).
339     *
340     * @return the facets
341     * @since 5.4.2
342     */
343    Set<String> getAllFacets();
344
345    /**
346     * Gets the facets defined on this document instance. The type facets are not returned.
347     *
348     * @return the facets
349     * @since 5.4.2
350     */
351    String[] getFacets();
352
353    /**
354     * Checks whether this document has a given facet, either from its type or added on the instance.
355     *
356     * @param facet the facet name
357     * @return {@code true} if the document has the facet
358     * @since 5.4.2
359     */
360    boolean hasFacet(String facet);
361
362    /**
363     * Adds a facet to this document.
364     * <p>
365     * Does nothing if the facet was already present on the document.
366     *
367     * @param facet the facet name
368     * @return {@code true} if the facet was added, or {@code false} if it is already present
369     * @throws IllegalArgumentException if the facet does not exist
370     * @since 5.4.2
371     */
372    boolean addFacet(String facet);
373
374    /**
375     * Removes a facet from this document.
376     * <p>
377     * It's not possible to remove a facet coming from the document type.
378     *
379     * @param facet the facet name
380     * @return {@code true} if the facet was removed, or {@code false} if it isn't present or is present on the type or
381     *         does not exit
382     * @since 5.4.2
383     */
384    boolean removeFacet(String facet);
385
386    /**
387     * Sets a lock on this document.
388     *
389     * @param lock the lock to set
390     * @return {@code null} if locking succeeded, or the existing lock if locking failed
391     */
392    Lock setLock(Lock lock);
393
394    /**
395     * Removes a lock from this document.
396     *
397     * @param the owner to check, or {@code null} for no check
398     * @return {@code null} if there was no lock or if removal succeeded, or a lock if it blocks removal due to owner
399     *         mismatch
400     */
401    Lock removeLock(String owner);
402
403    /**
404     * Gets the lock if one set on this document.
405     *
406     * @return the lock, or {@code null} if no lock is set
407     */
408    Lock getLock();
409
410    /**
411     * Gets a child document given its name.
412     * <p>
413     * Throws {@link DocumentNotFoundException} if the document could not be found.
414     *
415     * @param name the name of the child to retrieve
416     * @return the child if exists
417     * @throws DocumentNotFoundException if the child does not exist
418     */
419    Document getChild(String name);
420
421    /**
422     * Gets the children of the document.
423     * <p>
424     * Returns an empty list for non-folder documents.
425     *
426     * @return the children
427     */
428    List<Document> getChildren();
429
430    /**
431     * Gets a list of the children ids.
432     * <p>
433     * Returns an empty list for non-folder documents.
434     *
435     * @return a list of children ids.
436     * @since 1.4.1
437     */
438    List<String> getChildrenIds();
439
440    /**
441     * Checks whether this document has a child of the given name.
442     * <p>
443     * Returns {@code false} for non-folder documents.
444     *
445     * @param name the name of the child to check
446     * @return {@code true} if the child exists, {@code false} otherwise
447     */
448    boolean hasChild(String name);
449
450    /**
451     * Tests if the document has any children.
452     * <p>
453     * Returns {@code false} for non-folder documents.
454     *
455     * @return {@code true} if the document has children, {@code false} otherwise
456     */
457    boolean hasChildren();
458
459    /**
460     * Creates a new child document of the given type.
461     * <p>
462     * Throws an error if this document is not a folder.
463     *
464     * @param name the name of the new child to create
465     * @param typeName the type of the child to create
466     * @return the newly created document
467     */
468    Document addChild(String name, String typeName);
469
470    /**
471     * Orders the given source child before the destination child.
472     * <p>
473     * Both source and destination must be names that point to child documents of this document. The source document
474     * will be placed before the destination one. If destination is {@code null}, the source document will be appended
475     * at the end of the children list.
476     *
477     * @param src the document to move
478     * @param dest the document before which to place the source document
479     */
480    void orderBefore(String src, String dest);
481
482    /**
483     * Creates a new version.
484     *
485     * @param label the version label
486     * @param checkinComment the checkin comment
487     * @return the created version
488     */
489    Document checkIn(String label, String checkinComment);
490
491    void checkOut();
492
493    /**
494     * Gets the list of version ids for this document.
495     *
496     * @return the list of version ids
497     * @since 1.4.1
498     */
499    List<String> getVersionsIds();
500
501    /**
502     * Gets the versions for this document.
503     *
504     * @return the versions of the document, or an empty list if there are no versions
505     */
506    List<Document> getVersions();
507
508    /**
509     * Gets the last version of this document.
510     * <p>
511     * Returns {@code null} if there is no version at all.
512     *
513     * @return the last version, or {@code null} if there is no version
514     */
515    Document getLastVersion();
516
517    /**
518     * Gets the source for this document.
519     * <p>
520     * For a version, it's the working copy.
521     * <p>
522     * For a proxy, it's the version the proxy points to.
523     *
524     * @return the source document
525     */
526    Document getSourceDocument();
527
528    /**
529     * Replaces this document's content with the version specified.
530     *
531     * @param version the version to replace with
532     */
533    void restore(Document version);
534
535    /**
536     * Gets a version of this document, given its label.
537     *
538     * @param label the version label
539     * @return the version
540     */
541    Document getVersion(String label);
542
543    /**
544     * Checks whether this document is a version document.
545     *
546     * @return {@code true} if it's a version, {@code false} otherwise
547     */
548    boolean isVersion();
549
550    /**
551     * Gets the version to which a checked in document is linked.
552     * <p>
553     * Returns {@code null} for a checked out document or a version or a proxy.
554     *
555     * @return the version, or {@code null}
556     */
557    Document getBaseVersion();
558
559    /**
560     * Checks whether this document is checked out.
561     *
562     * @return {@code true} if the document is checked out, or {@code false} otherwise
563     */
564    boolean isCheckedOut();
565
566    /**
567     * Gets the version creation date of this document if it's a version or a proxy.
568     *
569     * @return the version creation date, or {@code null} if it's not a version or a proxy
570     */
571    Calendar getVersionCreationDate();
572
573    /**
574     * Gets the version check in comment of this document if it's a version or a proxy.
575     *
576     * @return the check in comment, or {@code null} if it's not a version or a proxy
577     */
578    String getCheckinComment();
579
580    /**
581     * Gets the version series id.
582     *
583     * @return the version series id
584     */
585    String getVersionSeriesId();
586
587    /**
588     * Gets the version label.
589     *
590     * @return the version label
591     */
592    String getVersionLabel();
593
594    /**
595     * Checks whether this document is the latest version.
596     *
597     * @return {@code true} if this is the latest version, or {@code false} otherwise
598     */
599    boolean isLatestVersion();
600
601    /**
602     * Checks whether this document is a major version.
603     *
604     * @return {@code true} if this is a major version, or {@code false} otherwise
605     */
606    boolean isMajorVersion();
607
608    /**
609     * Checks whether this document is the latest major version.
610     *
611     * @return {@code true} if this is the latest major version, or {@code false} otherwise
612     */
613    boolean isLatestMajorVersion();
614
615    /**
616     * Checks if there is a checked out working copy for the version series of this document.
617     *
618     * @return {@code true} if there is a checked out working copy
619     */
620    boolean isVersionSeriesCheckedOut();
621
622    /**
623     * Gets the working copy for this document.
624     *
625     * @return the working copy
626     */
627    Document getWorkingCopy();
628
629    /**
630     * Gets the document (version or live document) to which this proxy points.
631     */
632    Document getTargetDocument();
633
634    /**
635     * Sets the document (version or live document) to which this proxy points.
636     */
637    void setTargetDocument(Document target);
638
639}