/*
* Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Bogdan Stefanescu
* Florent Guillaume
*/
package org.eclipse.ecr.core.api;
import java.io.Serializable;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import org.eclipse.ecr.core.api.model.DocumentPart;
import org.eclipse.ecr.core.api.model.Property;
import org.eclipse.ecr.core.api.model.PropertyException;
import org.eclipse.ecr.core.api.security.ACP;
import org.eclipse.ecr.core.schema.DocumentType;
import org.nuxeo.common.collections.ScopeType;
import org.nuxeo.common.collections.ScopedMap;
import org.nuxeo.common.utils.Path;
/**
* The document model is a serializable representation of a core document.
* <p>
* The document model is made from several data models, each data model is bound
* to a schema. All the information about a document (like security) is
* expressed using schemas (and implicitly data models).
* <p>
* Data models are lazily loaded as they are needed. At document model creation
* only data models corresponding to the default schemas are loaded. The default
* schemas are configured in the type manager through extension points.
* <p>
* The user may overwrite the default schemas by passing the schemas to be used
* at model creation via {@link CoreSession#getDocument(DocumentRef, String[])}
* <p>
* How a lazy data model is loaded depends on the implementation.
* <p>
* Anyway the API already provides a mechanism to handle this as follow:
*
* <pre>
* <code>
* public DataModel getDataModel(String schema) {
* DataModel dataModel = dataModels.get(schema);
* if (dataModel != null && !dataModel.isLoaded()) {
* CoreSession client = CoreInstance.getInstance().getClient(
* getSessionId());
* if (client != null) {
* dataModel = client.getDataModel(getRef(), schema);
* dataModels.put(schema, dataModel);
* }
* }
* return dataModel;
* }
* </code>
* </pre>
*
* @see CoreSession
* @see DataModel
* @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
*/
public interface DocumentModel extends Serializable {
int REFRESH_STATE = 1; // "small" state (life cycle, lock, versioning)
int REFRESH_PREFETCH = 4;
int REFRESH_ACP_IF_LOADED = 8; // refresh now only if already loaded
int REFRESH_ACP_LAZY = 16; // refresh later in lazy mode
int REFRESH_ACP = 32; // refresh now
int REFRESH_CONTENT_IF_LOADED = 64; // refresh now only if already loaded
int REFRESH_CONTENT_LAZY = 128; // refresh later in lazy mode
int REFRESH_CONTENT = 256; // refresh now
int REFRESH_IF_LOADED = REFRESH_STATE | REFRESH_PREFETCH
| REFRESH_ACP_IF_LOADED | REFRESH_CONTENT_IF_LOADED;
int REFRESH_LAZY = REFRESH_STATE | REFRESH_PREFETCH | REFRESH_ACP_LAZY
| REFRESH_CONTENT_LAZY;
int REFRESH_ALL = REFRESH_STATE | REFRESH_PREFETCH | REFRESH_ACP
| REFRESH_CONTENT;
int REFRESH_DEFAULT = REFRESH_STATE | REFRESH_PREFETCH
| REFRESH_ACP_IF_LOADED | REFRESH_CONTENT_LAZY;
/**
* Gets the document type object.
*
* @return the document type object
*/
DocumentType getDocumentType();
/**
* Retrieves the session id corresponding to this object.
* <p>
* This method should rarely be used, use {@link #getCoreSession} directly
* instead.
* <p>
* Using the session id you can retrieve the core session that created the
* object.
* <p>
* Document models created by the user on the client side are not bound to
* any session. They are simple DTO used to transport data.
*
* @return the session id the session ID for server side created doc models
* or null for client side models (used for data transportation)
*/
String getSessionId();
/**
* Gets the core session to which this document is tied.
* <p>
* This may be null if the document has been detached from a session.
*
* @return the core session
* @since 5.2.GA
*/
CoreSession getCoreSession();
/**
* Gets a reference to the core document that can be used either remotely or
* locally (opens the core JVM).
*
* @return the document reference
*/
DocumentRef getRef();
/**
* Retrieves the parent reference of the current document.
*
* @return the parent reference or null if no parent
*/
DocumentRef getParentRef();
/**
* Gets the document UUID.
*
* @return the document UUID
*/
String getId();
/**
* Gets the document name.
*
* @return the document name
*/
String getName();
/**
* Get a text suitable to be shown in a UI for this document.
*
* @return the title or the internal name if no title could be found
* @throws ClientException
*/
String getTitle() throws ClientException;
/**
* Gets the document path as a string.
*
* @return the document path as string
*/
String getPathAsString();
/**
* Gets the document path.
*
* @return the document path as string
*/
Path getPath();
/**
* Gets the document type name.
*
* @return the document type name
*/
String getType();
/**
* Gets the schemas available on this document (from the type and the
* facets).
*
* @return the schemas
*
* @since 5.4.2
*/
String[] getSchemas();
/**
* Gets the schemas available on this document (from the type and the
* facets).
*
* @deprecated use {@link #getSchemas} instead, or call
* {@link #getDocumentType} and look up the type schemas
*
* @return the schemas
*/
@Deprecated
String[] getDeclaredSchemas();
/**
* Checks if the document has the given schema, either from its type or
* added on the instance through a facet.
*
* @param schema the schema name
* @return {@code true} if the document has the schema
*/
boolean hasSchema(String schema);
/**
* Gets the facets available on this document (from the type and the
* instance facets).
*
* @return the facets
*
* @since 5.4.2
*/
Set<String> getFacets();
/**
* Gets the facets available on this document (from the type and the
* instance facets).
*
* @deprecated use {@link #getFacets} instead, or call
* {@link #getDocumentType} and look up the type facets
*
* @return the facets
*/
@Deprecated
Set<String> getDeclaredFacets();
/**
* Checks if the document has a facet, either from its type or added on the
* instance.
*
* @param facet the facet name
* @return {@code true} if the document has the facet
*/
boolean hasFacet(String facet);
/**
* Adds a facet to the document instance.
* <p>
* Does nothing if the facet was already present on the document.
*
* @param facet the facet name
* @return {@code true} if the facet was added, or {@code false} if it is
* already present
* @throws DocumentException if the facet does not exist
*
* @since 5.4.2
*/
boolean addFacet(String facet);
/**
* Removes a facet from the document instance.
* <p>
* It's not possible to remove a facet coming from the document type.
*
* @param facet the facet name
* @return {@code true} if the facet was removed, or {@code false} if it
* isn't present or is present on the type or does not exit
*
* @since 5.4.2
*/
boolean removeFacet(String facet);
/**
* Gets a list with the currently fetched data models.
*
* @return the data models that are already fetched as a collection
*/
Collection<DataModel> getDataModelsCollection();
/**
* Gets the data models.
*
* @return the data models that are already fetched.
*/
DataModelMap getDataModels();
/**
* Gets the data model corresponding to the given schema.
* <p>
* Null is returned if the document type has no such schema.
*
* @param schema the schema name
* @return the data model or null if no such schema is supported
* @throws ClientException
*/
DataModel getDataModel(String schema) throws ClientException;
/**
* Sets path info.
* <p>
* path and ref attributes will be set according to info
*
* @param parentPath
* @param name
*/
void setPathInfo(String parentPath, String name);
/**
* Gets the lock key if the document is locked.
* <p>
* Lock info is cached on the document for performance. Use
* {@link CoreSession#getLockInfo} to get the non-cached status.
*
* @return the lock key if the document is locked or null otherwise
*
* @deprecated since 5.4.2, use {@link #getLockInfo} instead
*/
@Deprecated
String getLock();
/**
* Tests if the document is locked.
* <p>
* Lock info is cached on the document for performance. Use
* {@link CoreSession#getLockInfo} to get the non-cached status.
*
* @return the lock key if the document is locked or null otherwise
*/
boolean isLocked();
/**
* Locks this document using the given key.
* <p>
* This is a wrapper for {@link CoreSession#setLock(DocumentRef, String)}.
*
* @param key the key to use when locking
* @throws ClientException if the document is already locked or other error
* occurs
*
* @deprecated since 5.4.2, use {@link #setLock} instead
*/
@Deprecated
void setLock(String key) throws ClientException;
/**
* Unlocks the given document.
*
* @throws ClientException if the document is already locked or other error
* occurs
*
* @deprecated since 5.4.2, use {@link #removeLock} instead
*/
@Deprecated
void unlock() throws ClientException;
/**
* Sets a lock on the document.
*
* @return the lock info that was set
* @throws ClientException if a lock was already set
*
* @since 5.4.2
*/
Lock setLock() throws ClientException;
/**
* Gets the lock info on the document.
* <p>
* Lock info is cached on the document for performance. Use
* {@link CoreSession#getLockInfo} to get the non-cached status.
*
* @return the lock info if the document is locked, or {@code null}
* otherwise
*
* @since 5.4.2
*/
Lock getLockInfo() throws ClientException;
/**
* Removes the lock on the document.
* <p>
* The caller principal should be the same as the one who set the lock or to
* belongs to the administrator group, otherwise an exception will be throw.
* <p>
* If the document was not locked, does nothing.
* <p>
* Returns the previous lock info.
*
* @return the removed lock info, or {@code null} if there was no lock
*
* @since 5.4.2
*/
Lock removeLock() throws ClientException;
/**
* Tests if the document is checked out.
* <p>
* A checked out document can be modified normally. A checked in document is
* identical to the last version that it created, and not modifiable.
* <p>
* Only applicable to documents that are live (not versions and not
* proxies).
*
* @return {@code true} if the document is checked out, {@code false} if it
* is checked in
* @since 5.4
*/
boolean isCheckedOut() throws ClientException;
/**
* Checks out a document.
* <p>
* A checked out document can be modified normally.
* <p>
* Only applicable to documents that are live (not versions and not
* proxies).
*
* @since 5.4
*/
void checkOut() throws ClientException;
/**
* Checks in a document and returns the created version.
* <p>
* A checked in document is identical to the last version that it created,
* and not modifiable.
* <p>
* Only applicable to documents that are live (not versions and not
* proxies).
*
* @param option whether to do create a new {@link VersioningOption#MINOR}
* or {@link VersioningOption#MAJOR} version during check in
* @param checkinComment the checkin comment
* @return the version just created
* @since 5.4
*/
DocumentRef checkIn(VersioningOption option, String checkinComment)
throws ClientException;
/**
* Returns the version label.
* <p>
* The label returned is computed by the VersioningService.
*
* @return the version label, or {@code null}
*/
String getVersionLabel();
/**
* Returns the checkin comment if the document model is a version.
*
* @return the checkin comment, or {@code null}
* @since 5.4
*/
String getCheckinComment() throws ClientException;
/**
* Gets the version series id for this document.
* <p>
* All documents and versions derived by a check in or checkout from the
* same original document share the same version series id.
*
* @return the version series id
* @since 5.4
*/
String getVersionSeriesId() throws ClientException;
/**
* Checks if a document is the latest version in the version series.
* @since 5.4
*/
boolean isLatestVersion() throws ClientException;
/**
* Checks if a document is a major version.
* @since 5.4
*/
boolean isMajorVersion() throws ClientException;
/**
* Checks if a document is the latest major version in the version series.
* @since 5.4
*/
boolean isLatestMajorVersion() throws ClientException;
/**
* Checks if there is a checked out working copy for the version series of
* this document.
* @since 5.4
*/
boolean isVersionSeriesCheckedOut() throws ClientException;
/**
* Gets the access control policy (ACP) for this document.
* <p>
* Returns null if no security was defined on this document.
* <p>
* The ACP can be used to introspect or to evaluate user privileges on this
* document.
* <p>
* This is a wrapper for {@link CoreSession#getACP(DocumentRef)} but it is
* recommended since it caches the ACP for later usage.
*
* @return the security data model or null if none
* @throws ClientException
*/
ACP getACP() throws ClientException;
/**
* Sets the ACP for this document model.
* <p>
* This is a wrapper for
* {@link CoreSession#setACP(DocumentRef, ACP, boolean)}
*
* @see {@link CoreSession#setACP(DocumentRef, ACP, boolean)}
* @param acp the ACP to set
* @param overwrite whether to overwrite the old ACP or not
* @throws ClientException
*/
void setACP(ACP acp, boolean overwrite) throws ClientException;
/**
* Gets a property from the given schema.
* <p>
* The data model owning the property will be fetched from the server if not
* already fetched.
*
* @param schemaName the schema name
* @param name the property name
* @return the property value or null if no such property exists
* @throws ClientException
*/
Object getProperty(String schemaName, String name) throws ClientException;
/**
* Sets the property value from the given schema.
* <p>
* This operation will not fetch the data model if not already fetched
*
* @param schemaName the schema name
* @param name the property name
* @param value the property value
* @throws ClientException
*/
void setProperty(String schemaName, String name, Object value)
throws ClientException;
/**
* Gets the values from the given data model as a map.
* <p>
* The operation will fetch the data model from the server if not already
* fetched.
*
* @param schemaName the data model schema name
* @return the values map
* @throws ClientException
*/
Map<String, Object> getProperties(String schemaName) throws ClientException;
/**
* Sets values for the given data model.
* <p>
* This will not fetch the data model if not already fetched.
*
* @param schemaName the schema name
* @param data the values to set
* @throws ClientException
*/
void setProperties(String schemaName, Map<String, Object> data)
throws ClientException;
/**
* Checks if this document is a folder.
*
* @return true if the document is a folder, false otherwise
*/
boolean isFolder();
/**
* Checks if this document can have versions.
*
* @return true if the document can have versions, false otherwise
*/
boolean isVersionable();
/**
* Checks if this document can be downloaded.
*
* @return true if the document has downloadable content, false otherwise
* @throws ClientException
*/
boolean isDownloadable() throws ClientException;
/**
* Checks if this document is a version.
*
* @return true if the document is an older version of another document,
* false otherwise
*/
boolean isVersion();
/**
* Checks if this document is a proxy.
*
* @return true if the document is a proxy false otherwise
*/
boolean isProxy();
/**
* Checks if this document is immutable.
*
* @return {@code true} if the document is a version or a proxy to a
* version, {@code false} otherwise
* @since 1.6.1 (5.3.1)
*/
boolean isImmutable();
/**
* Adapts the document to the given interface.
*
* <p>
* Attention, the first computation will cache the adaptation result for
* later calls.
* </p>
*
* @param <T> the interface type to adapt to
* @param itf the interface class
* @return the adapted document
*/
<T> T getAdapter(Class<T> itf);
/**
* Adapts the document to the given interface.
*
* @param <T> the interface type to adapt to
* @param itf the interface class
* @param refreshCache : readapt and stores in cache if already exists.
* @return the adapted document
*/
<T> T getAdapter(Class<T> itf, boolean refreshCache);
/**
* Returns the life cycle of the document.
*
* @see org.eclipse.ecr.core.lifecycle
*
* @return the life cycle as a string
*/
String getCurrentLifeCycleState() throws ClientException;
/**
* Returns the life cycle policy of the document.
*
* @see org.eclipse.ecr.core.lifecycle
*
* @return the life cycle policy
*/
String getLifeCyclePolicy() throws ClientException;
/**
* Follows a given life cycle transition.
* <p>
* This will update the current life cycle of the document.
*
* @param transition the name of the transition to follow
* @return a boolean representing the status if the operation
*/
boolean followTransition(String transition) throws ClientException;
/**
* Gets the allowed state transitions for this document.
*
* @return a collection of state transitions as string
*/
Collection<String> getAllowedStateTransitions() throws ClientException;
/**
* Gets the context data associated to this document.
*
* @return serializable map of context data.
*/
ScopedMap getContextData();
/**
* Gets the context data associated to this document for given scope and
* given key.
*/
Serializable getContextData(ScopeType scope, String key);
/**
* Adds mapping to the context data for given scope.
* <p>
* Context data is like a request map set on the document model to pass
* additional information to components interacting with the document model
* (events processing for instance).
*/
void putContextData(ScopeType scope, String key, Serializable value);
/**
* Gets the context data using the default scope.
*
* @param key the context data key
* @return the value
*/
Serializable getContextData(String key);
/**
* Sets a context data in the default scope.
*
* @param key the context data key
* @param value the value
*/
void putContextData(String key, Serializable value);
/**
* Copies the context data from given document to this document.
*/
void copyContextData(DocumentModel otherDocument);
/**
* Copies all the data from a source document.
*/
void copyContent(DocumentModel sourceDoc) throws ClientException;
/**
* Returns the name of the repository in which the document is stored.
*
* @return the repository name as a string.
*/
String getRepositoryName();
/**
* Returns a cache key.
* <p>
* Cache key will be computed like this : <code>
* docUUID + "-" + sessionId + "-" + timestamp
* </code>
* <p>
* We will use the last modification time if present for the timestamp.
*
* @return the cache key as a string
* @throws ClientException
*/
String getCacheKey() throws ClientException;
/**
* Returns the source document identifier.
* <p>
* This is useful when not interested about the repository UUID itself.
* Technically, this is the current version UUID.
*
* @return the source id as a string.
*/
String getSourceId();
/**
* Returns the map of prefetched values.
*
* @return the map of prefetched values.
*/
Map<String, Serializable> getPrefetch();
/**
* Store a value in the prefetched inner map.
*/
void prefetchProperty(String id, Object value);
/**
* Used to set lifecycle state along with prefetching other properties.
*/
void prefetchCurrentLifecycleState(String lifecycle);
/**
* Used to set lifecycle policy along with prefetching other properties.
*/
void prefetchLifeCyclePolicy(String lifeCyclePolicy);
boolean isLifeCycleLoaded();
/**
* Gets system property of the specified type. This is not a lazy loaded
* property, thus the request is made directly to the server. This is needed
* as some critical system properties might be changed directly in the core.
*/
<T extends Serializable> T getSystemProp(String systemProperty,
Class<T> type) throws ClientException, DocumentException;
/**
* Get a document part given its schema name
*
* @param schema the schema
* @return the document aprt or null if none exists for that schema
* @throws ClientException
*/
// TODO throw an exception if schema is not impl by the doc?
DocumentPart getPart(String schema) throws ClientException;
/**
* Gets this document's parts.
*/
DocumentPart[] getParts() throws ClientException;
/**
* Gets a property given a xpath.
*/
Property getProperty(String xpath) throws PropertyException,
ClientException;
/**
* Gets a property value given a xpath.
*/
Serializable getPropertyValue(String xpath) throws PropertyException,
ClientException;
/**
* Sets a property value given a xpath.
*/
void setPropertyValue(String xpath, Serializable value)
throws PropertyException, ClientException;
/**
* Returns the flags set on the document model.
*/
long getFlags();
/**
* Clears any prefetched or cached document data.
* <p>
* This will force the document to lazily update its data when required.
*/
void reset();
/**
* Refresh document data from server.
* <p>
* The data models will be removed and all prefetch and system data will be
* refreshed from the server
* <p>
* The refreshed data contains:
* <ul>
* <li>document life cycle
* <li>document lock state, acp if required
* <li>document prefetch map
* <li>acp if required - otherwise acp info will be cleared so that it will
* be refetched in lazy way
* <li>document parts if required - otherwise parts data will be removed to
* be refreshed lazy
* </ul>
* The refresh flags are:
* <ul>
* <li> {@link DocumentModel#REFRESH_STATE}
* <li> {@link DocumentModel#REFRESH_PREFETCH}
* <li> {@link DocumentModel#REFRESH_ACP_IF_LOADED}
* <li> {@link DocumentModel#REFRESH_ACP_LAZY}
* <li> {@link DocumentModel#REFRESH_ACP}
* <li> {@link DocumentModel#REFRESH_CONTENT_IF_LOADED}
* <li> {@link DocumentModel#REFRESH_CONTENT_LAZY}
* <li> {@link DocumentModel#REFRESH_CONTENT}
* <li> {@link DocumentModel#REFRESH_DEFAULT} same as REFRESH_STATE |
* REFRESH_DEFAULT | REFRESH_ACP_IF_LOADED | REFRESH_CONTENT_IF_LOADED
* <li> {@link DocumentModel#REFRESH_ALL} same as REFRESH_STATE |
* REFRESH_PREFTECH | REFRESH_ACP | REFRESH_CONTENT
* </ul>
* If XX_IF_LOADED is used then XX will be refreshed only if already loaded
* in the document - otherwise a lazy refresh will be done
*
* @param refreshFlags the refresh flags
* @param schemas the document parts (schemas) that should be refreshed now
*/
void refresh(int refreshFlags, String[] schemas) throws ClientException;
/** Info fetched internally during a refresh. */
public static class DocumentModelRefresh {
public String lifeCycleState;
public String lifeCyclePolicy;
public boolean isCheckedOut;
public boolean isLatestVersion;
public boolean isMajorVersion;
public boolean isLatestMajorVersion;
public boolean isVersionSeriesCheckedOut;
public String versionSeriesId;
public String checkinComment;
public ACP acp;
public Map<String, Serializable> prefetch;
public DocumentPart[] documentParts;
}
/**
* Same as {@code DocumentModel.refresh(REFRESH_DEFAULT)}.
*/
void refresh() throws ClientException;
/**
* Clone operation. Must be made public instead of just protected as in
* Object.
*/
DocumentModel clone() throws CloneNotSupportedException;
}