001/*
002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     Bogdan Stefanescu
011 *     Florent Guillaume
012 */
013
014package org.nuxeo.ecm.core.api;
015
016import java.io.Serializable;
017import java.util.Collection;
018import java.util.Map;
019import java.util.Set;
020
021import org.nuxeo.common.collections.ScopeType;
022import org.nuxeo.common.collections.ScopedMap;
023import org.nuxeo.common.utils.Path;
024import org.nuxeo.ecm.core.api.model.DocumentPart;
025import org.nuxeo.ecm.core.api.model.Property;
026import org.nuxeo.ecm.core.api.model.PropertyVisitor;
027import org.nuxeo.ecm.core.api.model.resolver.PropertyObjectResolver;
028import org.nuxeo.ecm.core.api.security.ACP;
029import org.nuxeo.ecm.core.schema.DocumentType;
030import org.nuxeo.ecm.core.schema.Prefetch;
031
032/**
033 * The document model is a serializable representation of a core document.
034 * <p>
035 * The document model is made from several data models, each data model is bound to a schema. All the information about
036 * a document (like security) is expressed using schemas (and implicitly data models).
037 * <p>
038 * Data models are lazily loaded as they are needed. At document model creation only data models corresponding to the
039 * default schemas are loaded. The default schemas are configured in the type manager through extension points.
040 * <p>
041 * The user may overwrite the default schemas by passing the schemas to be used at model creation via
042 * {@link CoreSession#getDocument(DocumentRef, String[])}
043 * <p>
044 * How a lazy data model is loaded depends on the implementation.
045 * <p>
046 * Anyway the API already provides a mechanism to handle this as follow:
047 *
048 * <pre>
049 * <code>
050 * public DataModel getDataModel(String schema) {
051 *     DataModel dataModel = dataModels.get(schema);
052 *     if (dataModel != null &amp;&amp; !dataModel.isLoaded()) {
053 *         CoreSession client = CoreInstance.getInstance().getClient(
054 *                 getSessionId());
055 *         if (client != null) {
056 *             dataModel = client.getDataModel(getRef(), schema);
057 *             dataModels.put(schema, dataModel);
058 *         }
059 *     }
060 *     return dataModel;
061 * }
062 * </code>
063 * </pre>
064 *
065 * @see CoreSession
066 * @see DataModel
067 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
068 */
069public interface DocumentModel extends Serializable {
070
071    int REFRESH_STATE = 1; // "small" state (life cycle, lock, versioning)
072
073    int REFRESH_PREFETCH = 4;
074
075    int REFRESH_ACP_IF_LOADED = 8; // refresh now only if already loaded
076
077    int REFRESH_ACP_LAZY = 16; // refresh later in lazy mode
078
079    int REFRESH_ACP = 32; // refresh now
080
081    int REFRESH_CONTENT_IF_LOADED = 64; // refresh now only if already loaded
082
083    int REFRESH_CONTENT_LAZY = 128; // refresh later in lazy mode
084
085    int REFRESH_CONTENT = 256; // refresh now
086
087    int REFRESH_IF_LOADED = REFRESH_STATE | REFRESH_PREFETCH | REFRESH_ACP_IF_LOADED | REFRESH_CONTENT_IF_LOADED;
088
089    int REFRESH_LAZY = REFRESH_STATE | REFRESH_PREFETCH | REFRESH_ACP_LAZY | REFRESH_CONTENT_LAZY;
090
091    int REFRESH_ALL = REFRESH_STATE | REFRESH_PREFETCH | REFRESH_ACP | REFRESH_CONTENT;
092
093    int REFRESH_DEFAULT = REFRESH_STATE | REFRESH_PREFETCH | REFRESH_ACP_IF_LOADED | REFRESH_CONTENT_LAZY;
094
095    /**
096     * Gets the document type object.
097     *
098     * @return the document type object
099     */
100    DocumentType getDocumentType();
101
102    /**
103     * Retrieves the session id corresponding to this object.
104     * <p>
105     * This method should rarely be used, use {@link #getCoreSession} directly instead.
106     * <p>
107     * Using the session id you can retrieve the core session that created the object.
108     * <p>
109     * Document models created by the user on the client side are not bound to any session. They are simple DTO used to
110     * transport data.
111     *
112     * @return the session id the session ID for server side created doc models or null for client side models (used for
113     *         data transportation)
114     */
115    String getSessionId();
116
117    /**
118     * Gets the core session to which this document is tied.
119     * <p>
120     * This may be null if the document has been detached from a session.
121     *
122     * @return the core session
123     * @since 5.2.GA
124     */
125    CoreSession getCoreSession();
126
127    /**
128     * Detaches the documentImpl from its existing session, so that it can survive beyond the session's closing.
129     *
130     * @param loadAll if {@code true}, load all data and ACP from the session before detaching
131     * @since 5.6
132     */
133    void detach(boolean loadAll);
134
135    /**
136     * Reattaches a document impl to an existing session.
137     *
138     * @param sid the session id
139     * @since 5.6
140     */
141    void attach(String sid);
142
143    /**
144     * Gets a reference to the core document that can be used either remotely or locally (opens the core JVM).
145     *
146     * @return the document reference
147     */
148    DocumentRef getRef();
149
150    /**
151     * Retrieves the parent reference of the current document.
152     *
153     * @return the parent reference or null if no parent
154     */
155    DocumentRef getParentRef();
156
157    /**
158     * Gets the document UUID.
159     *
160     * @return the document UUID
161     */
162    String getId();
163
164    /**
165     * Gets the document name.
166     *
167     * @return the document name
168     */
169    String getName();
170
171    /**
172     * Gets the document's position in its containing folder (if ordered).
173     *
174     * @return the position, or {@code null} if the containing folder is not ordered
175     * @since 6.0
176     */
177    Long getPos();
178
179    /**
180     * Get a text suitable to be shown in a UI for this document.
181     *
182     * @return the title or the internal name if no title could be found
183     */
184    String getTitle();
185
186    /**
187     * Gets the document path as a string.
188     *
189     * @return the document path as string
190     */
191    String getPathAsString();
192
193    /**
194     * Gets the document path.
195     *
196     * @return the document path as string
197     */
198    Path getPath();
199
200    /**
201     * Gets the document type name.
202     *
203     * @return the document type name
204     */
205    String getType();
206
207    /**
208     * Gets the schemas available on this document (from the type and the facets).
209     *
210     * @return the schemas
211     * @since 5.4.2
212     */
213    String[] getSchemas();
214
215    /**
216     * Gets the schemas available on this document (from the type and the facets).
217     *
218     * @deprecated use {@link #getSchemas} instead, or call {@link #getDocumentType} and look up the type schemas
219     * @return the schemas
220     */
221    @Deprecated
222    String[] getDeclaredSchemas();
223
224    /**
225     * Checks if the document has the given schema, either from its type or added on the instance through a facet.
226     *
227     * @param schema the schema name
228     * @return {@code true} if the document has the schema
229     */
230    boolean hasSchema(String schema);
231
232    /**
233     * Gets the facets available on this document (from the type and the instance facets).
234     *
235     * @return the facets
236     * @since 5.4.2
237     */
238    Set<String> getFacets();
239
240    /**
241     * Gets the facets available on this document (from the type and the instance facets).
242     *
243     * @deprecated use {@link #getFacets} instead, or call {@link #getDocumentType} and look up the type facets
244     * @return the facets
245     */
246    @Deprecated
247    Set<String> getDeclaredFacets();
248
249    /**
250     * Checks if the document has a facet, either from its type or added on the instance.
251     *
252     * @param facet the facet name
253     * @return {@code true} if the document has the facet
254     */
255    boolean hasFacet(String facet);
256
257    /**
258     * Adds a facet to the document instance.
259     * <p>
260     * Does nothing if the facet was already present on the document.
261     *
262     * @param facet the facet name
263     * @return {@code true} if the facet was added, or {@code false} if it is already present
264     * @throws IllegalArgumentException if the facet does not exist
265     * @since 5.4.2
266     */
267    boolean addFacet(String facet);
268
269    /**
270     * Removes a facet from the document instance.
271     * <p>
272     * It's not possible to remove a facet coming from the document type.
273     *
274     * @param facet the facet name
275     * @return {@code true} if the facet was removed, or {@code false} if it isn't present or is present on the type or
276     *         does not exit
277     * @since 5.4.2
278     */
279    boolean removeFacet(String facet);
280
281    /**
282     * Gets a list with the currently fetched data models.
283     *
284     * @return the data models that are already fetched as a collection
285     */
286    Collection<DataModel> getDataModelsCollection();
287
288    /**
289     * Gets the data models.
290     *
291     * @return the data models that are already fetched.
292     */
293    DataModelMap getDataModels();
294
295    /**
296     * Gets the data model corresponding to the given schema.
297     * <p>
298     * Null is returned if the document type has no such schema.
299     *
300     * @param schema the schema name
301     * @return the data model or null if no such schema is supported
302     */
303    DataModel getDataModel(String schema);
304
305    /**
306     * Sets path info.
307     * <p>
308     * path and ref attributes will be set according to info
309     *
310     * @param parentPath
311     * @param name
312     */
313    void setPathInfo(String parentPath, String name);
314
315    /**
316     * Gets the lock key if the document is locked.
317     * <p>
318     * Lock info is cached on the document for performance. Use {@link CoreSession#getLockInfo} to get the non-cached
319     * status.
320     *
321     * @return the lock key if the document is locked or null otherwise
322     * @deprecated since 5.4.2, use {@link #getLockInfo} instead
323     */
324    @Deprecated
325    String getLock();
326
327    /**
328     * Tests if the document is locked.
329     * <p>
330     * Lock info is cached on the document for performance. Use {@link CoreSession#getLockInfo} to get the non-cached
331     * status.
332     *
333     * @return the lock key if the document is locked or null otherwise
334     */
335    boolean isLocked();
336
337    /**
338     * Locks this document using the given key.
339     * <p>
340     * This is a wrapper for {@link CoreSession#setLock(DocumentRef, String)}.
341     *
342     * @param key the key to use when locking
343     * @throws LockException if the document is already locked
344     * @deprecated since 5.4.2, use {@link #setLock} instead
345     */
346    @Deprecated
347    void setLock(String key) throws LockException;
348
349    /**
350     * Unlocks the given document.
351     *
352     * @throws LockException if the document is locked by someone else
353     * @deprecated since 5.4.2, use {@link #removeLock} instead
354     */
355    @Deprecated
356    void unlock() throws LockException;
357
358    /**
359     * Sets a lock on the document.
360     *
361     * @return the lock info that was set
362     * @throws LockException if the document is already locked
363     * @since 5.4.2
364     */
365    Lock setLock() throws LockException;
366
367    /**
368     * Gets the lock info on the document.
369     * <p>
370     * Lock info is cached on the document for performance. Use {@link CoreSession#getLockInfo} to get the non-cached
371     * status.
372     *
373     * @return the lock info if the document is locked, or {@code null} otherwise
374     * @since 5.4.2
375     */
376    Lock getLockInfo();
377
378    /**
379     * Removes the lock on the document.
380     * <p>
381     * The caller principal should be the same as the one who set the lock or to belongs to the administrator group,
382     * otherwise an exception will be throw.
383     * <p>
384     * If the document was not locked, does nothing.
385     * <p>
386     * Returns the previous lock info.
387     *
388     * @return the removed lock info, or {@code null} if there was no lock
389     * @throws LockException if the document is locked by someone else
390     * @since 5.4.2
391     */
392    Lock removeLock() throws LockException;
393
394    /**
395     * Tests if the document is checked out.
396     * <p>
397     * A checked out document can be modified normally. A checked in document is identical to the last version that it
398     * created, and not modifiable.
399     * <p>
400     * Only applicable to documents that are live (not versions and not proxies).
401     *
402     * @return {@code true} if the document is checked out, {@code false} if it is checked in
403     * @since 5.4
404     */
405    boolean isCheckedOut();
406
407    /**
408     * Checks out a document.
409     * <p>
410     * A checked out document can be modified normally.
411     * <p>
412     * Only applicable to documents that are live (not versions and not proxies).
413     *
414     * @since 5.4
415     */
416    void checkOut();
417
418    /**
419     * Checks in a document and returns the created version.
420     * <p>
421     * A checked in document is identical to the last version that it created, and not modifiable.
422     * <p>
423     * Only applicable to documents that are live (not versions and not proxies).
424     *
425     * @param option whether to do create a new {@link VersioningOption#MINOR} or {@link VersioningOption#MAJOR} version
426     *            during check in
427     * @param checkinComment the checkin comment
428     * @return the version just created
429     * @since 5.4
430     */
431    DocumentRef checkIn(VersioningOption option, String checkinComment);
432
433    /**
434     * Returns the version label.
435     * <p>
436     * The label returned is computed by the VersioningService.
437     *
438     * @return the version label, or {@code null}
439     */
440    String getVersionLabel();
441
442    /**
443     * Returns the checkin comment if the document model is a version.
444     *
445     * @return the checkin comment, or {@code null}
446     * @since 5.4
447     */
448    String getCheckinComment();
449
450    /**
451     * Gets the version series id for this document.
452     * <p>
453     * All documents and versions derived by a check in or checkout from the same original document share the same
454     * version series id.
455     *
456     * @return the version series id
457     * @since 5.4
458     */
459    String getVersionSeriesId();
460
461    /**
462     * Checks if a document is the latest version in the version series.
463     *
464     * @since 5.4
465     */
466    boolean isLatestVersion();
467
468    /**
469     * Checks if a document is a major version.
470     *
471     * @since 5.4
472     */
473    boolean isMajorVersion();
474
475    /**
476     * Checks if a document is the latest major version in the version series.
477     *
478     * @since 5.4
479     */
480    boolean isLatestMajorVersion();
481
482    /**
483     * Checks if there is a checked out working copy for the version series of this document.
484     *
485     * @since 5.4
486     */
487    boolean isVersionSeriesCheckedOut();
488
489    /**
490     * Gets the access control policy (ACP) for this document.
491     * <p>
492     * Returns null if no security was defined on this document.
493     * <p>
494     * The ACP can be used to introspect or to evaluate user privileges on this document.
495     * <p>
496     * This is a wrapper for {@link CoreSession#getACP(DocumentRef)} but it is recommended since it caches the ACP for
497     * later usage.
498     *
499     * @return the security data model or null if none
500     */
501    ACP getACP();
502
503    /**
504     * Sets the ACP for this document model.
505     * <p>
506     * This is a wrapper for {@link CoreSession#setACP(DocumentRef, ACP, boolean)}
507     *
508     * @see {@link CoreSession#setACP(DocumentRef, ACP, boolean)}
509     * @param acp the ACP to set
510     * @param overwrite whether to overwrite the old ACP or not
511     */
512    void setACP(ACP acp, boolean overwrite);
513
514    /**
515     * Gets a property from the given schema.
516     * <p>
517     * The data model owning the property will be fetched from the server if not already fetched.
518     *
519     * @param schemaName the schema name
520     * @param name the property name
521     * @return the property value or null if no such property exists
522     */
523    Object getProperty(String schemaName, String name);
524
525    /**
526     * Sets the property value from the given schema.
527     * <p>
528     * This operation will not fetch the data model if not already fetched
529     *
530     * @param schemaName the schema name
531     * @param name the property name
532     * @param value the property value
533     */
534    void setProperty(String schemaName, String name, Object value);
535
536    /**
537     * Gets the values from the given data model as a map.
538     * <p>
539     * The operation will fetch the data model from the server if not already fetched.
540     *
541     * @param schemaName the data model schema name
542     * @return the values map
543     */
544    Map<String, Object> getProperties(String schemaName);
545
546    /**
547     * Sets values for the given data model.
548     * <p>
549     * This will not fetch the data model if not already fetched.
550     *
551     * @param schemaName the schema name
552     * @param data the values to set
553     */
554    void setProperties(String schemaName, Map<String, Object> data);
555
556    /**
557     * Checks if this document is a folder.
558     *
559     * @return true if the document is a folder, false otherwise
560     */
561    boolean isFolder();
562
563    /**
564     * Checks if this document can have versions.
565     *
566     * @return true if the document can have versions, false otherwise
567     */
568    boolean isVersionable();
569
570    /**
571     * Checks if this document can be downloaded.
572     *
573     * @return true if the document has downloadable content, false otherwise
574     */
575    boolean isDownloadable();
576
577    /**
578     * Checks if this document is a version.
579     *
580     * @return true if the document is an older version of another document, false otherwise
581     */
582    boolean isVersion();
583
584    /**
585     * Checks if this document is a proxy.
586     *
587     * @return true if the document is a proxy false otherwise
588     */
589    boolean isProxy();
590
591    /**
592     * Checks if this document is immutable.
593     *
594     * @return {@code true} if the document is a version or a proxy to a version, {@code false} otherwise
595     * @since 1.6.1 (5.3.1)
596     */
597    boolean isImmutable();
598
599    /**
600     * Checks if the document has actual data to write (dirty parts).
601     *
602     * @since 5.5
603     */
604    boolean isDirty();
605
606    /**
607     * Method that implement the visitor pattern.
608     * <p>
609     * The visitor must return null to stop visiting children otherwise a context object that will be passed as the arg
610     * argument to children
611     *
612     * @param visitor the visitor to accept
613     * @param arg an argument passed to the visitor. This should be used by the visitor to carry on the visiting
614     *            context.
615     * @since 5.5
616     */
617    void accept(PropertyVisitor visitor, Object arg);
618
619    /**
620     * Adapts the document to the given interface.
621     * <p>
622     * Attention, the first computation will cache the adaptation result for later calls.
623     * </p>
624     *
625     * @param <T> the interface type to adapt to
626     * @param itf the interface class
627     * @return the adapted document
628     */
629    <T> T getAdapter(Class<T> itf);
630
631    /**
632     * Adapts the document to the given interface.
633     *
634     * @param <T> the interface type to adapt to
635     * @param itf the interface class
636     * @param refreshCache : readapt and stores in cache if already exists.
637     * @return the adapted document
638     */
639    <T> T getAdapter(Class<T> itf, boolean refreshCache);
640
641    /**
642     * Returns the life cycle of the document.
643     *
644     * @see org.nuxeo.ecm.core.lifecycle
645     * @return the life cycle as a string
646     */
647    String getCurrentLifeCycleState();
648
649    /**
650     * Returns the life cycle policy of the document.
651     *
652     * @see org.nuxeo.ecm.core.lifecycle
653     * @return the life cycle policy
654     */
655    String getLifeCyclePolicy();
656
657    /**
658     * Follows a given life cycle transition.
659     * <p>
660     * This will update the current life cycle of the document.
661     *
662     * @param transition the name of the transition to follow
663     * @return a boolean representing the status if the operation
664     */
665    boolean followTransition(String transition);
666
667    /**
668     * Gets the allowed state transitions for this document.
669     *
670     * @return a collection of state transitions as string
671     */
672    Collection<String> getAllowedStateTransitions();
673
674    /**
675     * Gets the context data associated to this document.
676     *
677     * @return serializable map of context data.
678     */
679    ScopedMap getContextData();
680
681    /**
682     * Gets the context data associated to this document for given scope and given key.
683     */
684    Serializable getContextData(ScopeType scope, String key);
685
686    /**
687     * Adds mapping to the context data for given scope.
688     * <p>
689     * Context data is like a request map set on the document model to pass additional information to components
690     * interacting with the document model (events processing for instance).
691     */
692    void putContextData(ScopeType scope, String key, Serializable value);
693
694    /**
695     * Gets the context data using the default scope.
696     *
697     * @param key the context data key
698     * @return the value
699     */
700    Serializable getContextData(String key);
701
702    /**
703     * Sets a context data in the default scope.
704     *
705     * @param key the context data key
706     * @param value the value
707     */
708    void putContextData(String key, Serializable value);
709
710    /**
711     * Copies the context data from given document to this document.
712     */
713    void copyContextData(DocumentModel otherDocument);
714
715    /**
716     * Copies all the data from a source document.
717     */
718    void copyContent(DocumentModel sourceDoc);
719
720    /**
721     * Returns the name of the repository in which the document is stored.
722     *
723     * @return the repository name as a string.
724     */
725    String getRepositoryName();
726
727    /**
728     * Returns a cache key.
729     * <p>
730     * Cache key will be computed like this : <code>
731     *     docUUID + "-" + sessionId + "-" + timestamp
732     *   </code>
733     * <p>
734     * We will use the last modification time if present for the timestamp.
735     * <p>
736     * Since 5.6, the timestamp does not hold milliseconds anymore as some databases do not store them, which could
737     * interfere with cache key comparisons.
738     *
739     * @return the cache key as a string
740     */
741    String getCacheKey();
742
743    /**
744     * Returns the source document identifier.
745     * <p>
746     * This is useful when not interested about the repository UUID itself. Technically, this is the current version
747     * UUID.
748     *
749     * @return the source id as a string.
750     */
751    String getSourceId();
752
753    /**
754     * Checks if a property is prefetched.
755     *
756     * @param xpath the property xpath
757     * @return {@code true} if it is prefetched
758     * @since 5.5
759     */
760    boolean isPrefetched(String xpath);
761
762    /**
763     * Checks if a property is prefetched.
764     *
765     * @param schemaName the schema name
766     * @param name the property name
767     * @return {@code true} if it is prefetched
768     * @since 5.5
769     */
770    boolean isPrefetched(String schemaName, String name);
771
772    /**
773     * Used to set lifecycle state along with prefetching other properties.
774     */
775    void prefetchCurrentLifecycleState(String lifecycle);
776
777    /**
778     * Used to set lifecycle policy along with prefetching other properties.
779     */
780    void prefetchLifeCyclePolicy(String lifeCyclePolicy);
781
782    boolean isLifeCycleLoaded();
783
784    /**
785     * Gets system property of the specified type. This is not a lazy loaded property, thus the request is made directly
786     * to the server. This is needed as some critical system properties might be changed directly in the core.
787     */
788    <T extends Serializable> T getSystemProp(String systemProperty, Class<T> type);
789
790    /**
791     * Get a document part given its schema name
792     *
793     * @param schema the schema
794     * @return the document aprt or null if none exists for that schema
795     */
796    // TODO throw an exception if schema is not impl by the doc?
797    DocumentPart getPart(String schema);
798
799    /**
800     * Gets this document's parts.
801     */
802    DocumentPart[] getParts();
803
804    /**
805     * Gets a property given a xpath.
806     * <p>
807     * Note that what's called xpath in this context is not an actual XPath as specified by the w3c. Main differences
808     * are that in our xpath:
809     * <ul>
810     * <li>Indexes start at 0 instead of 1</li>
811     * <li>You can express {@code foo/bar[i]/baz} as {@code foo/i/baz}</li>
812     * </ul>
813     * The latter is possible because in Nuxeo lists of complex elements are homogenous, so the name of the second-level
814     * element is implied.
815     */
816    Property getProperty(String xpath) throws PropertyException;
817
818    /**
819     * Gets a property value given a xpath.
820     * <p>
821     * Note that what's called xpath in this context is not an actual XPath as specified by the w3c. Main differences
822     * are that in our xpath:
823     * <ul>
824     * <li>Indexes start at 0 instead of 1</li>
825     * <li>You can express {@code foo/bar[i]/baz} as {@code foo/i/baz}</li>
826     * </ul>
827     * The latter is possible because in Nuxeo lists of complex elements are homogenous, so the name of the second-level
828     * element is implied.
829     */
830    Serializable getPropertyValue(String xpath) throws PropertyException;
831
832    /**
833     * Sets a property value given a xpath.
834     */
835    void setPropertyValue(String xpath, Serializable value) throws PropertyException;
836
837    /**
838     * Clears any prefetched or cached document data.
839     * <p>
840     * This will force the document to lazily update its data when required.
841     */
842    void reset();
843
844    /**
845     * Refresh document data from server.
846     * <p>
847     * The data models will be removed and all prefetch and system data will be refreshed from the server
848     * <p>
849     * The refreshed data contains:
850     * <ul>
851     * <li>document life cycle
852     * <li>document lock state, acp if required
853     * <li>document prefetch map
854     * <li>acp if required - otherwise acp info will be cleared so that it will be refetched in lazy way
855     * <li>document parts if required - otherwise parts data will be removed to be refreshed lazy
856     * </ul>
857     * The refresh flags are:
858     * <ul>
859     * <li> {@link DocumentModel#REFRESH_STATE}
860     * <li> {@link DocumentModel#REFRESH_PREFETCH}
861     * <li> {@link DocumentModel#REFRESH_ACP_IF_LOADED}
862     * <li> {@link DocumentModel#REFRESH_ACP_LAZY}
863     * <li> {@link DocumentModel#REFRESH_ACP}
864     * <li> {@link DocumentModel#REFRESH_CONTENT_IF_LOADED}
865     * <li> {@link DocumentModel#REFRESH_CONTENT_LAZY}
866     * <li> {@link DocumentModel#REFRESH_CONTENT}
867     * <li> {@link DocumentModel#REFRESH_DEFAULT} same as REFRESH_STATE | REFRESH_DEFAULT | REFRESH_ACP_IF_LOADED |
868     * REFRESH_CONTENT_IF_LOADED
869     * <li> {@link DocumentModel#REFRESH_ALL} same as REFRESH_STATE | REFRESH_PREFTECH | REFRESH_ACP | REFRESH_CONTENT
870     * </ul>
871     * If XX_IF_LOADED is used then XX will be refreshed only if already loaded in the document - otherwise a lazy
872     * refresh will be done
873     *
874     * @param refreshFlags the refresh flags
875     * @param schemas the document parts (schemas) that should be refreshed now
876     */
877    void refresh(int refreshFlags, String[] schemas);
878
879    /** Info fetched internally during a refresh. */
880    public static class DocumentModelRefresh {
881
882        public String lifeCycleState;
883
884        public String lifeCyclePolicy;
885
886        public boolean isCheckedOut;
887
888        public boolean isLatestVersion;
889
890        public boolean isMajorVersion;
891
892        public boolean isLatestMajorVersion;
893
894        public boolean isVersionSeriesCheckedOut;
895
896        public String versionSeriesId;
897
898        public String checkinComment;
899
900        public ACP acp;
901
902        public Prefetch prefetch;
903
904        public Set<String> instanceFacets;
905
906        public DocumentPart[] documentParts;
907    }
908
909    /**
910     * Same as {@code DocumentModel.refresh(REFRESH_DEFAULT)}.
911     */
912    void refresh();
913
914    /**
915     * Clone operation. Must be made public instead of just protected as in Object.
916     */
917    DocumentModel clone() throws CloneNotSupportedException;
918
919    /**
920     * Opaque string that represents the last update state of the DocumentModel.
921     * <p>
922     * This token can be used for optimistic locking and avoid dirty updates. See CMIS spec :
923     * http://docs.oasis-open.org/cmis/CMIS/v1.0/os/cmis-spec-v1.0.html#_Toc243905432
924     *
925     * @since 5.5
926     * @return the ChangeToken string that can be null for some Document types
927     */
928    String getChangeToken();
929
930    /**
931     * Gets the fulltext extracted from the binary fields.
932     *
933     * @since 5.9.3
934     */
935    Map<String, String> getBinaryFulltext();
936
937    /**
938     * @param xpath the property xpath
939     * @return A {@link PropertyObjectResolver} to manage the property reference to external entities, null if this
940     *         property's type has no resolver.
941     * @since 7.1
942     */
943    PropertyObjectResolver getObjectResolver(String xpath);
944
945}