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