content: /*
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you under the Apache License, Version 2.0 (the
   * "License"); you may not use this file except in compliance
   * with the License.  You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing,
   * software distributed under the License is distributed on an
   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   * KIND, either express or implied.  See the License for the
   * specific language governing permissions and limitations
   * under the License.
   */
  package org.apache.chemistry.opencmis.client.api;
  
  import java.io.Serializable;
  import java.math.BigInteger;
  import java.util.Collection;
  import java.util.List;
  import java.util.Locale;
  import java.util.Map;
  import java.util.Set;
  
  import org.apache.chemistry.opencmis.commons.data.Ace;
  import org.apache.chemistry.opencmis.commons.data.Acl;
  import org.apache.chemistry.opencmis.commons.data.BulkUpdateObjectIdAndChangeToken;
  import org.apache.chemistry.opencmis.commons.data.ContentStream;
  import org.apache.chemistry.opencmis.commons.data.RepositoryInfo;
  import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
  import org.apache.chemistry.opencmis.commons.enums.AclPropagation;
  import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
  import org.apache.chemistry.opencmis.commons.enums.RelationshipDirection;
  import org.apache.chemistry.opencmis.commons.enums.UnfileObject;
  import org.apache.chemistry.opencmis.commons.enums.VersioningState;
  import org.apache.chemistry.opencmis.commons.exceptions.CmisBaseException;
  import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
  import org.apache.chemistry.opencmis.commons.spi.CmisBinding;
  
  /**
   * A session is a connection to a CMIS repository with a specific user.
   * <p>
   * CMIS itself is stateless. OpenCMIS uses the concept of a session to cache
   * data across calls and to deal with user authentication. The session object is
   * also used as entry point to all CMIS operations and objects. Because a
   * session is only a client side concept, the session object needs not to be
   * closed or released when it's not needed anymore.
   * <p>
   * Not all operations provided by this API might be supported by the connected
   * repository. Either OpenCMIS or the repository will throw an exception if an
   * unsupported operation is called. The capabilities of the repository can be
   * discovered by evaluating the repository info (see
   * {@link #getRepositoryInfo()}).
   * <p>
   * Almost all methods might throw exceptions derived from
   * {@link CmisBaseException} which is a runtime exception. See the CMIS
   * specification for a list of all operations and their exceptions. Note that
   * some incompliant repositories might throw other exception than you expect.
   * <p>
   * Refer to the <a href="https://docs.oasis-open.org/cmis/CMIS/v1.0/os/">CMIS 1.0
   * specification</a> or the
   * <a href="https://docs.oasis-open.org/cmis/CMIS/v1.0/os/">CMIS 1.1
   * specification</a> for details about the domain model, terms, concepts, base
   * types, properties, IDs and query names, query language, etc.
   * </p>
   */
  public interface Session extends Serializable {
  
      /**
       * Clears all cached data.
       */
      void clear();
  
      // session context
  
      /**
       * Returns the underlying binding object.
       * 
       * @return the binding object, not {@code null}
       */
      CmisBinding getBinding();
  
      /**
       * Returns the session parameters that were used to create this session.
       * 
       * @return the session parameters, a unmodifiable Map, not {@code null}
       */
      Map<String, String> getSessionParameters();
  
      /**
       * Returns the current default operation parameters for filtering, paging
       * and caching.
       * 
       * <p>
       * <em>Please note:</em> The returned object is not thread-safe and should
       * only be modified right after the session has been created and before the
       * session object has been used. In order to change the default context in
       * thread-safe manner, create a new {@link OperationContext} object and use
       * {@link #setDefaultContext(OperationContext)} to apply it.
       * </p>
       * 
       * @return the default operation context, not {@code null}
       */
      OperationContext getDefaultContext();
  
      /**
       * Sets the current session parameters for filtering, paging and caching.
       * 
       * @param context
       *            the {@code OperationContext} to be used for the session; if
       *            {@code null}, a default context is used
       */
      void setDefaultContext(OperationContext context);
  
      /**
       * Creates a new operation context object.
       * 
       * @return the newly created operation context object
       */
      OperationContext createOperationContext();
  
      /**
       * Creates a new operation context object with the given properties.
       * 
       * @param filter
       *            the property filter, a comma separated string of <em>query
       *            names</em> or "*" for all properties or {@code null} to let
       *            the repository determine a set of properties
       * @param includeAcls
       *            indicates whether ACLs should be included or not
       * @param includeAllowableActions
       *            indicates whether Allowable Actions should be included or not
       * @param includePolicies
       *            indicates whether policies should be included or not
       * @param includeRelationships
       *            enum that indicates if and which relationships should be
       *            includes
       * @param renditionFilter
       *            the rendition filter or {@code null} for no renditions
       * @param includePathSegments
       *            indicates whether path segment or the relative path segment
       *            should be included or not
       * @param orderBy
       *            the object order, a comma-separated list of <em>query
       *            names</em> and the ascending modifier "ASC" or the descending
       *            modifier "DESC" for each query name
       * @param cacheEnabled
       *            flag that indicates if the object cache should be used
       * @param maxItemsPerPage
       *            the max items per batch
       * 
       * @return the newly created operation context object
       * 
       * @see OperationContext
       */
      OperationContext createOperationContext(Set<String> filter, boolean includeAcls, boolean includeAllowableActions,
              boolean includePolicies, IncludeRelationships includeRelationships, Set<String> renditionFilter,
              boolean includePathSegments, String orderBy, boolean cacheEnabled, int maxItemsPerPage);
  
      /**
       * Creates an object ID from a String.
       * 
       * @return the object ID object
       */
      ObjectId createObjectId(String id);
  
      // localization
  
      /**
       * Get the current locale to be used for this session.
       * 
       * @return the current locale, may be {@code null}
       */
      Locale getLocale();
  
      // services
  
      /**
       * Returns the repository info of the repository associated with this
       * session.
       * 
       * @return the repository info, not {@code null}
       * 
       * @cmis 1.0
       */
      RepositoryInfo getRepositoryInfo();
  
      /**
       * Gets a factory object that provides methods to create the objects used by
       * this API.
       * 
       * @return the repository info, not {@code null}
       */
      ObjectFactory getObjectFactory();
  
      // types
  
      /**
       * Gets the definition of a type.
       * 
       * @param typeId
       *            the ID of the type
       * 
       * @return the type definition
       * 
       * @throws CmisObjectNotFoundException
       *             if a type with the given type ID doesn't exist
       * 
       * @cmis 1.0
       */
      ObjectType getTypeDefinition(String typeId);
  
      /**
       * Gets the definition of a type.
       * 
       * @param typeId
       *            the ID of the type
       * @param useCache
       *            specifies if the type definition should be first looked up in
       *            the type definition cache, if it is set to {@code false} or
       *            the type definition is not in the cache, the type definition
       *            is loaded from the repository
       * 
       * @return the type definition
       * 
       * @throws CmisObjectNotFoundException
       *             if a type with the given type ID doesn't exist
       * 
       * @cmis 1.0
       */
      ObjectType getTypeDefinition(String typeId, boolean useCache);
  
      /**
       * Gets the type children of a type.
       * 
       * @param typeId
       *            the type ID or {@code null} to request the base types
       * @param includePropertyDefinitions
       *            indicates whether the property definitions should be included
       *            or not
       * @return the type iterator, not {@code null}
       * 
       * @throws CmisObjectNotFoundException
       *             if a type with the given type ID doesn't exist
       * 
       * @cmis 1.0
       */
      ItemIterable<ObjectType> getTypeChildren(String typeId, boolean includePropertyDefinitions);
  
      /**
       * Gets the type descendants of a type.
       * 
       * @param typeId
       *            the type ID or {@code null} to request the base types
       * @param depth
       *            the tree depth, must be greater than 0 or -1 for infinite
       *            depth
       * @param includePropertyDefinitions
       *            indicates whether the property definitions should be included
       *            or not
       * @return the tree of types
       * 
       * @throws CmisObjectNotFoundException
       *             if a type with the given type ID doesn't exist
       * 
       * @cmis 1.0
       */
      List<Tree<ObjectType>> getTypeDescendants(String typeId, int depth, boolean includePropertyDefinitions);
  
      /**
       * Creates a new type.
       * 
       * @param type
       *            the type definition
       * 
       * @return the new type definition
       * 
       * @cmis 1.1
       */
      ObjectType createType(TypeDefinition type);
  
      /**
       * Updates an existing type.
       * 
       * @param type
       *            the type definition updates
       * 
       * @return the updated type definition
       * 
       * @cmis 1.1
       */
      ObjectType updateType(TypeDefinition type);
  
      /**
       * Deletes a type.
       * 
       * @param typeId
       *            the ID of the type to delete
       * 
       * @cmis 1.1
       */
      void deleteType(String typeId);
  
      // navigation
  
      /**
       * Gets the root folder of the repository.
       * 
       * @return the root folder object, not {@code null}
       * 
       * @cmis 1.0
       */
      Folder getRootFolder();
  
      /**
       * Gets the root folder of the repository with the given
       * {@link OperationContext}.
       * 
       * @return the root folder object, not {@code null}
       * 
       * @cmis 1.0
       */
      Folder getRootFolder(OperationContext context);
  
      /**
       * Returns all checked out documents.
       * 
       * @see Folder#getCheckedOutDocs()
       * 
       * @cmis 1.0
       */
      ItemIterable<Document> getCheckedOutDocs();
  
      /**
       * Returns all checked out documents with the given {@link OperationContext}
       * .
       * 
       * @see Folder#getCheckedOutDocs(OperationContext)
       * 
       * @cmis 1.0
       */
      ItemIterable<Document> getCheckedOutDocs(OperationContext context);
  
      /**
       * Returns a CMIS object from the session cache. If the object is not in the
       * cache or the cache is turned off per default {@link OperationContext}, it
       * will load the object from the repository and puts it into the cache.
       * <p>
       * This method might return a stale object if the object has been found in
       * the cache and has been changed in or removed from the repository. Use
       * {@link CmisObject#refresh()} and {@link CmisObject#refreshIfOld(long)} to
       * update the object if necessary.
       * 
       * @param objectId
       *            the object ID
       * 
       * @return the requested object
       * 
       * @throws CmisObjectNotFoundException
       *             if an object with the given ID doesn't exist
       * 
       * @see #getObject(String)
       * 
       * @cmis 1.0
       */
      CmisObject getObject(ObjectId objectId);
  
      /**
       * Returns a CMIS object from the session cache. If the object is not in the
       * cache or the given {@link OperationContext} has caching turned off, it
       * will load the object from the repository and puts it into the cache.
       * <p>
       * This method might return a stale object if the object has been found in
       * the cache and has been changed in or removed from the repository. Use
       * {@link CmisObject#refresh()} and {@link CmisObject#refreshIfOld(long)} to
       * update the object if necessary.
       * 
       * @param objectId
       *            the object ID
       * @param context
       *            the {@link OperationContext} to use
       * 
       * @return the requested object
       * 
       * @throws CmisObjectNotFoundException
       *             if an object with the given ID doesn't exist
       * 
       * @see #getObject(String, OperationContext)
       * 
       * @cmis 1.0
       */
      CmisObject getObject(ObjectId objectId, OperationContext context);
  
      /**
       * Returns a CMIS object from the session cache. If the object is not in the
       * cache or the cache is turned off per default {@link OperationContext}, it
       * will load the object from the repository and puts it into the cache.
       * <p>
       * This method might return a stale object if the object has been found in
       * the cache and has been changed in or removed from the repository. Use
       * {@link CmisObject#refresh()} and {@link CmisObject#refreshIfOld(long)} to
       * update the object if necessary.
       * 
       * @param objectId
       *            the object ID
       * 
       * @return the requested object
       * 
       * @throws CmisObjectNotFoundException
       *             if an object with the given ID doesn't exist
       * 
       * @see #getObject(ObjectId)
       * 
       * @cmis 1.0
       */
      CmisObject getObject(String objectId);
  
      /**
       * Returns a CMIS object from the session cache. If the object is not in the
       * cache or the given {@link OperationContext} has caching turned off, it
       * will load the object from the repository and puts it into the cache.
       * <p>
       * This method might return a stale object if the object has been found in
       * the cache and has been changed in or removed from the repository. Use
       * {@link CmisObject#refresh()} and {@link CmisObject#refreshIfOld(long)} to
       * update the object if necessary.
       * 
       * @param objectId
       *            the object ID
       * @param context
       *            the {@link OperationContext} to use
       * 
       * @return the requested object
       * 
       * @throws CmisObjectNotFoundException
       *             if an object with the given ID doesn't exist
       * 
       * @see #getObject(ObjectId, OperationContext)
       * 
       * @cmis 1.0
       */
      CmisObject getObject(String objectId, OperationContext context);
  
      /**
       * Returns a CMIS object from the session cache. If the object is not in the
       * cache or the cache is turned off per default {@link OperationContext}, it
       * will load the object from the repository and puts it into the cache.
       * <p>
       * This method might return a stale object if the object has been found in
       * the cache and has been changed in or removed from the repository. Use
       * {@link CmisObject#refresh()} and {@link CmisObject#refreshIfOld(long)} to
       * update the object if necessary.
       * 
       * @param path
       *            the object path
       * 
       * @return the requested object
       * 
       * @throws CmisObjectNotFoundException
       *             if an object with the given ID doesn't exist
       * 
       * @cmis 1.0
       */
      CmisObject getObjectByPath(String path);
  
      /**
       * Returns a CMIS object from the session cache. If the object is not in the
       * cache or the given {@link OperationContext} has caching turned off, it
       * will load the object from the repository and puts it into the cache.
       * <p>
       * This method might return a stale object if the object has been found in
       * the cache and has been changed in or removed from the repository. Use
       * {@link CmisObject#refresh()} and {@link CmisObject#refreshIfOld(long)} to
       * update the object if necessary.
       * 
       * @param path
       *            the object path
       * @param context
       *            the {@link OperationContext} to use
       * 
       * @return the requested object
       * 
       * @throws CmisObjectNotFoundException
       *             if an object with the given ID doesn't exist
       * 
       * @cmis 1.0
       */
      CmisObject getObjectByPath(String path, OperationContext context);
  
      /**
       * Returns a CMIS object from the session cache. If the object is not in the
       * cache or the cache is turned off per default {@link OperationContext}, it
       * will load the object from the repository and puts it into the cache.
       * <p>
       * This method might return a stale object if the object has been found in
       * the cache and has been changed in or removed from the repository. Use
       * {@link CmisObject#refresh()} and {@link CmisObject#refreshIfOld(long)} to
       * update the object if necessary.
       * 
       * @param parentPath
       *            the path of the parent folder
       * @param name
       *            the (path segment) name of the object in the folder
       * 
       * @return the requested object
       * 
       * @throws CmisObjectNotFoundException
       *             if an object with the given ID doesn't exist
       * 
       * @cmis 1.0
       */
      CmisObject getObjectByPath(String parentPath, String name);
  
      /**
       * Returns a CMIS object from the session cache. If the object is not in the
       * cache or the given {@link OperationContext} has caching turned off, it
       * will load the object from the repository and puts it into the cache.
       * <p>
       * This method might return a stale object if the object has been found in
       * the cache and has been changed in or removed from the repository. Use
       * {@link CmisObject#refresh()} and {@link CmisObject#refreshIfOld(long)} to
       * update the object if necessary.
       * 
       * @param parentPath
       *            the path of the parent folder
       * @param name
       *            the (path segment) name of the object in the folder
       * @param context
       *            the {@link OperationContext} to use
       * 
       * @return the requested object
       * 
       * @throws CmisObjectNotFoundException
       *             if an object with the given ID doesn't exist
       * 
       * @cmis 1.0
       */
      CmisObject getObjectByPath(String parentPath, String name, OperationContext context);
  
      /**
       * Returns the latest version in a version series.
       * 
       * Some repositories throw an exception if the document is not versionable;
       * others just return the unversioned document. To avoid surprises, check
       * first whether the document is versionable or not.
       * 
       * @param objectId
       *            the document ID of an arbitrary version in the version series
       * 
       * @return the latest document version
       * 
       * @cmis 1.0
       */
      Document getLatestDocumentVersion(ObjectId objectId);
  
      /**
       * Returns the latest version in a version series.
       * 
       * Some repositories throw an exception if the document is not versionable;
       * others just return the unversioned document. To avoid surprises, check
       * first whether the document is versionable or not.
       * 
       * @param objectId
       *            the document ID of an arbitrary version in the version series
       * @param context
       *            the {@link OperationContext} to use
       * 
       * @return the latest document version
       * 
       * @cmis 1.0
       */
      Document getLatestDocumentVersion(ObjectId objectId, OperationContext context);
  
      /**
       * Returns the latest version in a version series.
       * 
       * Some repositories throw an exception if the document is not versionable;
       * others just return the unversioned document. To avoid surprises, check
       * first whether the document is versionable or not.
       * 
       * If {@code major} == {@code true} and the version series doesn't contain a
       * major version, the repository is supposed to throw a
       * {@link CmisObjectNotFoundException}.
       * 
       * @param objectId
       *            the document ID of an arbitrary version in the version series
       * @param major
       *            if {@code true} the latest major version will be returned,
       *            otherwise the very last version will be returned
       * @param context
       *            the {@link OperationContext} to use
       * 
       * @return the latest document version
       * 
       * @cmis 1.0
       */
      Document getLatestDocumentVersion(ObjectId objectId, boolean major, OperationContext context);
  
      /**
       * Returns the latest version in a version series.
       * 
       * Some repositories throw an exception if the document is not versionable;
       * others just return the unversioned document. To avoid surprises, check
       * first whether the document is versionable or not.
       * 
       * @param objectId
       *            the document ID of an arbitrary version in the version series
       * 
       * @return the latest document version
       * 
       * @cmis 1.0
       */
      Document getLatestDocumentVersion(String objectId);
  
      /**
       * Returns the latest version in a version series.
       * 
       * Some repositories throw an exception if the document is not versionable;
       * others just return the unversioned document. To avoid surprises, check
       * first whether the document is versionable or not.
       * 
       * @param objectId
       *            the document ID of an arbitrary version in the version series
       * @param context
       *            the {@link OperationContext} to use
       * 
       * @return the latest document version
       * 
       * @cmis 1.0
       */
      Document getLatestDocumentVersion(String objectId, OperationContext context);
  
      /**
       * Returns the latest version in a version series.
       * 
       * Some repositories throw an exception if the document is not versionable;
       * others just return the unversioned document. To avoid surprises, check
       * first whether the document is versionable or not.
       * 
       * If {@code major} == {@code true} and the version series doesn't contain a
       * major version, the repository is supposed to throw a
       * {@link CmisObjectNotFoundException}.
       * 
       * @param objectId
       *            the document ID of an arbitrary version in the version series
       * @param major
       *            if {@code true} the latest major version will be returned,
       *            otherwise the very last version will be returned
       * @param context
       *            the {@link OperationContext} to use
       * 
       * @return the latest document version
       * 
       * @cmis 1.0
       */
      Document getLatestDocumentVersion(String objectId, boolean major, OperationContext context);
  
      /**
       * Checks if an object with given object ID exists in the repository and is
       * visible for the current user.
       * 
       * If the object doesn't exist (anymore), it is removed from the cache.
       * 
       * @param objectId
       *            the object ID
       * @return {@code true} if the object exists in the repository,
       *         {@code false} otherwise
       * 
       * @cmis 1.0
       */
      boolean exists(ObjectId objectId);
  
      /**
       * Checks if an object with given object ID exists in the repository and is
       * visible for the current user.
       * 
       * If the object doesn't exist (anymore), it is removed from the cache.
       * 
       * @param objectId
       *            the object ID
       * @return {@code true} if the object exists in the repository,
       *         {@code false} otherwise
       * 
       * @cmis 1.0
       */
      boolean exists(String objectId);
  
      /**
       * Checks if an object with given path exists in the repository and is
       * visible for the current user.
       * 
       * If the object doesn't exist (anymore), it is removed from the cache.
       * 
       * @param path
       *            the path
       * @return {@code true} if the object exists in the repository,
       *         {@code false} otherwise
       * 
       * @cmis 1.0
       */
      boolean existsPath(String path);
  
      /**
       * Checks if an object with given path exists in the repository and is
       * visible for the current user.
       * 
       * If the object doesn't exist (anymore), it is removed from the cache.
       * 
       * @param parentPath
       *            the path of the parent folder
       * @param name
       *            the (path segment) name of the object in the folder
       * 
       * @return the requested object
       * 
       * @throws CmisObjectNotFoundException
       *             if an object with the given ID doesn't exist
       * 
       * @cmis 1.0
       */
      boolean existsPath(String parentPath, String name);
  
      /**
       * Removes the given object from the cache.
       * 
       * @param objectId
       *            object ID
       * 
       * @see #removeObjectFromCache(String)
       */
      void removeObjectFromCache(ObjectId objectId);
  
      /**
       * Removes the given object from the cache.
       * 
       * @param objectId
       *            object ID
       */
      void removeObjectFromCache(String objectId);
  
      // discovery
  
      /**
       * Sends a query to the repository. Refer to the CMIS specification for the
       * CMIS query language syntax.
       * 
       * @param statement
       *            the query statement (CMIS query language)
       * @param searchAllVersions
       *            specifies whether non-latest document versions should be
       *            included or not, {@code true} searches all document versions,
       *            {@code false} only searches latest document versions
       * 
       * @return an {@link Iterable} to iterate over the query result
       * 
       * @cmis 1.0
       */
      ItemIterable<QueryResult> query(String statement, boolean searchAllVersions);
  
      /**
       * Sends a query to the repository using the given {@link OperationContext}.
       * (See CMIS spec "2.1.10 Query".)
       * 
       * @param statement
       *            the query statement (CMIS query language)
       * @param searchAllVersions
       *            specifies whether non-latest document versions should be
       *            included or not, {@code true} searches all document versions,
       *            {@code false} only searches latest document versions
       * @param context
       *            the operation context to use
       * 
       * @return an {@link Iterable} to iterate over the query result
       * 
       * @cmis 1.0
       */
      ItemIterable<QueryResult> query(String statement, boolean searchAllVersions, OperationContext context);
  
      /**
       * Builds a CMIS query and returns the query results as an iterator of
       * {@link CmisObject} objects.
       * 
       * @param typeId
       *            the ID of the object type
       * @param where
       *            the WHERE part of the query
       * @param searchAllVersions
       *            specifies whether non-latest document versions should be
       *            included or not, {@code true} searches all document versions,
       *            {@code false} only searches latest document versions
       * @param context
       *            the operation context to use
       * 
       * @return an {@link Iterable} to iterate over the objects
       * 
       * @cmis 1.0
       */
      ItemIterable<CmisObject> queryObjects(String typeId, String where, boolean searchAllVersions,
              OperationContext context);
  
      /**
       * Creates a query statement.
       * <p>
       * Sample code:
       * 
       * <pre>
       * QueryStatement stmt = session
       *         .createQueryStatement(&quot;SELECT ?, ? FROM ? WHERE ? &gt; TIMESTAMP ? AND IN_FOLDER(?) OR ? IN (?)&quot;);
       * </pre>
       * 
       * @param statement
       *            the query statement with placeholders ('?'), see
       *            {@link QueryStatement} for details
       * 
       * @return a new query statement object
       * 
       * @see QueryStatement
       * 
       * @cmis 1.0
       */
      QueryStatement createQueryStatement(String statement);
  
      /**
       * Creates a query statement for a query of one primary type joined by zero
       * or more secondary types.
       * <p>
       * Sample code:
       * 
       * <pre>
       * List&lt;String&gt; select = new ArrayList&lt;String&gt;();
       * select.add(&quot;cmis:name&quot;);
       * select.add(&quot;SecondaryStringProp&quot;);
       * 
       * Map&lt;String, String&gt; from = new HashMap&lt;String, String&gt;();
       * from.put(&quot;d&quot;, &quot;cmis:document&quot;);
       * from.put(&quot;s&quot;, &quot;MySecondaryType&quot;);
       * 
       * String where = &quot;d.cmis:name LIKE ?&quot;;
       * 
       * List&lt;String&gt; orderBy = new ArrayList&lt;String&gt;();
       * orderBy.add(&quot;cmis:name&quot;);
       * orderBy.add(&quot;SecondaryIntegerProp&quot;);
       * 
       * QueryStatement stmt = session.createQueryStatement(select, from, where, orderBy);
       * </pre>
       * 
       * Generates something like this:
       * 
       * <pre>
       * SELECT d.cmis:name,s.SecondaryStringProp FROM cmis:document AS d JOIN MySecondaryType AS s ON d.cmis:objectId=s.cmis:objectId WHERE d.cmis:name LIKE ? ORDER BY d.cmis:name,s.SecondaryIntegerProp
       * </pre>
       * 
       * @param selectPropertyIds
       *            the property IDs in the SELECT statement, if {@code null} all
       *            properties are selected
       * @param fromTypes
       *            a Map of type aliases (keys) and type IDs (values), the Map
       *            must contain exactly one primary type and zero or more
       *            secondary types
       * @param whereClause
       *            an optional WHERE clause with placeholders ('?'), see
       *            {@link QueryStatement} for details
       * @param orderByPropertyIds
       *            an optional list of properties IDs for the ORDER BY clause
       * 
       * @return a new query statement object
       * 
       * @see QueryStatement
       * 
       * @cmis 1.0
       */
      QueryStatement createQueryStatement(Collection<String> selectPropertyIds, Map<String, String> fromTypes,
              String whereClause, List<String> orderByPropertyIds);
  
      /**
       * Returns the content changes.
       * 
       * @param changeLogToken
       *            the change log token to start from or {@code null} to start
       *            from the first available event in the repository
       * @param includeProperties
       *            indicates whether changed properties should be included in the
       *            result or not
       * @param maxNumItems
       *            maximum numbers of events
       * 
       * @return the change events
       * 
       * @cmis 1.0
       */
      ChangeEvents getContentChanges(String changeLogToken, boolean includeProperties, long maxNumItems);
  
      /**
       * Returns the content changes.
       * 
       * @param changeLogToken
       *            the change log token to start from or {@code null} to start
       *            from the first available event in the repository
       * @param includeProperties
       *            indicates whether changed properties should be included in the
       *            result or not
       * @param maxNumItems
       *            maximum numbers of events
       * @param context
       *            the OperationContext
       * 
       * @return the change events
       * 
       * @cmis 1.0
       */
      ChangeEvents getContentChanges(String changeLogToken, boolean includeProperties, long maxNumItems,
              OperationContext context);
  
      /**
       * Returns an iterator of content changes, starting from the given change
       * log token to the latest entry in the change log.
       * <p>
       * Note: Paging and skipping are not supported.
       * 
       * @param changeLogToken
       *            the change log token to start from or {@code null} to start
       *            from the first available event in the repository
       * @param includeProperties
       *            indicates whether changed properties should be included in the
       *            result or not
       * 
       * @cmis 1.0
       */
      ItemIterable<ChangeEvent> getContentChanges(String changeLogToken, boolean includeProperties);
  
      /**
       * Returns an iterator of content changes, starting from the given change
       * log token to the latest entry in the change log.
       * <p>
       * Note: Paging and skipping are not supported.
       * 
       * @param changeLogToken
       *            the change log token to start from or {@code null} to start
       *            from the first available event in the repository
       * @param includeProperties
       *            indicates whether changed properties should be included in the
       *            result or not
       * @param context
       *            the OperationContext
       * 
       * @cmis 1.0
       */
      ItemIterable<ChangeEvent> getContentChanges(final String changeLogToken, final boolean includeProperties,
              OperationContext context);
  
      /**
       * Returns the latest change log token.
       * <p>
       * In contrast to the repository info, this change log token is not cached.
       * This method requests the token from the repository every single time it
       * is called.
       * 
       * @return the latest change log token or {@code null} if the repository
       *         doesn't provide one
       * 
       * @cmis 1.0
       */
      String getLatestChangeLogToken();
  
      // create
  
      /**
       * Creates a new document.
       * 
       * The stream in {@code contentStream} is consumed but not closed by this
       * method.
       * 
       * @return the object ID of the new document
       * 
       * @see Folder#createDocument(Map, ContentStream, VersioningState, List,
       *      List, List, OperationContext)
       * 
       * @cmis 1.0
       */
      ObjectId createDocument(Map<String, ?> properties, ObjectId folderId, ContentStream contentStream,
              VersioningState versioningState, List<Policy> policies, List<Ace> addAces, List<Ace> removeAces);
  
      /**
       * Creates a new document.
       * 
       * The stream in {@code contentStream} is consumed but not closed by this
       * method.
       * 
       * @return the object ID of the new document
       * 
       * @see Folder#createDocument(Map, ContentStream, VersioningState, List,
       *      List, List, OperationContext)
       * 
       * @cmis 1.0
       */
      ObjectId createDocument(Map<String, ?> properties, ObjectId folderId, ContentStream contentStream,
              VersioningState versioningState);
  
      /**
       * Creates a new document from a source document.
       * 
       * @return the object ID of the new document
       * 
       * @see Folder#createDocumentFromSource(ObjectId, Map, VersioningState,
       *      List, List, List, OperationContext)
       * 
       * @cmis 1.0
       */
      ObjectId createDocumentFromSource(ObjectId source, Map<String, ?> properties, ObjectId folderId,
              VersioningState versioningState, List<Policy> policies, List<Ace> addAces, List<Ace> removeAces);
  
      /**
       * Creates a new document from a source document.
       * 
       * @return the object ID of the new document
       * 
       * @see Folder#createDocumentFromSource(ObjectId, Map, VersioningState,
       *      List, List, List, OperationContext)
       * 
       * @cmis 1.0
       */
      ObjectId createDocumentFromSource(ObjectId source, Map<String, ?> properties, ObjectId folderId,
              VersioningState versioningState);
  
      /**
       * Creates a new folder.
       * 
       * @param properties
       *            the folder properties
       * @param folderId
       *            the folder ID of the parent folder, not {@code null}
       * 
       * @return the object ID of the new folder
       * 
       * @see Folder#createFolder(Map, List, List, List, OperationContext)
       * 
       * @cmis 1.0
       */
      ObjectId createFolder(Map<String, ?> properties, ObjectId folderId, List<Policy> policies, List<Ace> addAces,
              List<Ace> removeAces);
  
      /**
       * Creates a new folder.
       * 
       * @param properties
       *            the folder properties
       * @param folderId
       *            the folder ID of the parent folder, not {@code null}
       * 
       * @return the object ID of the new folder
       * 
       * @see Folder#createFolder(Map, List, List, List, OperationContext)
       * 
       * @cmis 1.0
       */
      ObjectId createFolder(Map<String, ?> properties, ObjectId folderId);
  
      /**
       * Creates a folder path.
       * 
       * All missing folders in the path are created. Existing folders are not
       * touched.
       * 
       * @param newPath
       *            the absolute path
       * @param typeId
       *            the type ID of all folders that are being created
       * 
       * @return the object ID of the deepest folder
       * 
       * @cmis 1.0
       */
      ObjectId createPath(String newPath, String typeId);
  
      /**
       * Creates a folder path.
       * 
       * All missing folders in the path are created. Existing folders are not
       * touched.
       * 
       * @param startFolderId
       *            the ID of a folder in the path that the path creation should
       *            start with, {@code null} for the root folder.
       * @param newPath
       *            the absolute path
       * @param typeId
       *            the type ID of all folders that are being created
       * 
       * @return the object ID of the deepest folder
       * 
       * @cmis 1.0
       */
      ObjectId createPath(ObjectId startFolderId, String newPath, String typeId);
  
      /**
       * Creates a folder path.
       * 
       * All missing folders in the path are created. Existing folders are not
       * touched.
       * 
       * @param newPath
       *            the absolute path
       * @param properties
       *            the properties of all folders that are being created
       * 
       * @return the object ID of the deepest folder
       * 
       * @cmis 1.0
       */
      ObjectId createPath(String newPath, Map<String, ?> properties);
  
      /**
       * Creates a folder path.
       * 
       * All missing folders in the path are created. Existing folders are not
       * touched.
       * 
       * @param startFolderId
       *            the ID of a folder in the path that the path creation should
       *            start with, {@code null} for the root folder
       * @param newPath
       *            the absolute path
       * @param properties
       *            the properties of all folders that are being created
       * 
       * @return the object ID of the deepest folder
       * 
       * @cmis 1.0
       */
      ObjectId createPath(ObjectId startFolderId, String newPath, Map<String, ?> properties);
  
      /**
       * Creates a folder path.
       * 
       * All missing folders in the path are created. Existing folders are not
       * touched.
       * 
       * @param startFolderId
       *            the ID of a folder in the path that the path creation should
       *            start with, {@code null} for the root folder
       * @param newPath
       *            the absolute path
       * @param properties
       *            the properties of all folders that are being created
       * 
       * @return the object ID of the deepest folder
       * 
       * @cmis 1.0
       */
      ObjectId createPath(ObjectId startFolderId, String newPath, Map<String, ?> properties, List<Policy> policies,
              List<Ace> addAces, List<Ace> removeAces);
  
      /**
       * Creates a new policy.
       * 
       * @param properties
       *            the policy properties
       * @param folderId
       *            the folder ID of the parent folder, {@code null} for an
       *            unfiled policy
       * 
       * @return the object ID of the new policy
       * 
       * @see Folder#createPolicy(Map, List, List, List, OperationContext)
       * 
       * @cmis 1.0
       */
      ObjectId createPolicy(Map<String, ?> properties, ObjectId folderId, List<Policy> policies, List<Ace> addAces,
              List<Ace> removeAces);
  
      /**
       * Creates a new policy.
       * 
       * @param properties
       *            the policy properties
       * @param folderId
       *            the folder ID of the parent folder, {@code null} for an
       *            unfiled policy
       * 
       * @return the object ID of the new policy
       * 
       * @see Folder#createPolicy(Map, List, List, List, OperationContext)
       * 
       * @cmis 1.0
       */
      ObjectId createPolicy(Map<String, ?> properties, ObjectId folderId);
  
      /**
       * Creates a new item.
       * 
       * @param properties
       *            the item properties
       * @param folderId
       *            the folder ID of the parent folder, {@code null} for an
       *            unfiled item
       * 
       * @return the object ID of the new policy
       * 
       * @see Folder#createItem(Map, List, List, List, OperationContext)
       * 
       * @cmis 1.1
       */
      ObjectId createItem(Map<String, ?> properties, ObjectId folderId, List<Policy> policies, List<Ace> addAces,
              List<Ace> removeAces);
  
      /**
       * Creates a new item.
       * 
       * @param properties
       *            the item properties
       * @param folderId
       *            the folder ID of the parent folder, {@code null} for an
       *            unfiled item
       * 
       * @return the object ID of the new item
       * 
       * @see Folder#createItem(Map, List, List, List, OperationContext)
       * 
       * @cmis 1.1
       */
      ObjectId createItem(Map<String, ?> properties, ObjectId folderId);
  
      /**
       * Creates a new relationship.
       *
       * @param properties
       *            the relationship properties
       *
       * @return the object ID of the new relationship
       * 
       * @cmis 1.0
       */
      ObjectId createRelationship(Map<String, ?> properties, List<Policy> policies, List<Ace> addAces,
              List<Ace> removeAces);
  
      /**
       * Creates a new relationship.
       * 
       * @param properties
       *            the relationship properties
       * 
       * @return the object ID of the new relationship
       * 
       * @cmis 1.0
       */
      ObjectId createRelationship(Map<String, ?> properties);
  
      /**
       * Fetches the relationships from or to an object from the repository.
       * 
       * @cmis 1.0
       */
      ItemIterable<Relationship> getRelationships(ObjectId objectId, boolean includeSubRelationshipTypes,
              RelationshipDirection relationshipDirection, ObjectType type, OperationContext context);
  
      /**
       * Updates multiple objects in one request.
       * 
       * @cmis 1.0
       */
      List<BulkUpdateObjectIdAndChangeToken> bulkUpdateProperties(List<CmisObject> objects, Map<String, ?> properties,
              List<String> addSecondaryTypeIds, List<String> removeSecondaryTypeIds);
  
      /**
       * Deletes an object and, if it is a document, all versions in the version
       * series.
       * 
       * @param objectId
       *            the ID of the object
       * 
       * @cmis 1.0
       */
      void delete(ObjectId objectId);
  
      /**
       * Deletes an object.
       * 
       * @param objectId
       *            the ID of the object
       * @param allVersions
       *            if this object is a document this parameter defines if only
       *            this version or all versions should be deleted
       * 
       * @cmis 1.0
       */
      void delete(ObjectId objectId, boolean allVersions);
  
      /**
       * Deletes an object by path and, if it is a document, all versions in the
       * version series.
       * 
       * @param path
       *            the path of the object
       * 
       * @cmis 1.0
       */
      public void deleteByPath(String path);
  
      /**
       * Deletes an object by path and, if it is a document, all versions in the
       * version series.
       * 
       * @param parentPath
       *            the path of the parent folder
       * @param name
       *            the (path segment) name of the object in the folder
       * 
       * @cmis 1.0
       */
      void deleteByPath(String parentPath, String name);
  
      /**
       * Deletes an object by path.
       * 
       * @param path
       *            the path of the object
       * @param allVersions
       *            if this object is a document this parameter defines if only
       *            this version or all versions should be deleted
       * 
       * @cmis 1.0
       */
      void deleteByPath(String path, boolean allVersions);
  
      /**
       * Deletes a folder and all subfolders.
       * 
       * @param folderId
       *            the ID of the folder
       * @param allVersions
       *            if this object is a document this parameter defines if only
       *            this version or all versions should be deleted
       * @param unfile
       *            defines how objects should be unfiled
       * @param continueOnFailure
       *            if {@code true} the repository tries to delete as many objects
       *            as possible; if {@code false} the repository stops at the
       *            first object that could not be deleted
       * 
       * @return a list of object IDs which failed to be deleted
       * 
       * @cmis 1.0
       */
      List<String> deleteTree(ObjectId folderId, boolean allVersions, UnfileObject unfile, boolean continueOnFailure);
  
      /**
       * Deletes a folder and all subfolders by path.
       * 
       * @param parentPath
       *            the path of the parent folder
       * @param name
       *            the (path segment) name of the folder in the parent folder
       * @param allVersions
       *            if this object is a document this parameter defines if only
       *            this version or all versions should be deleted
       * @param unfile
       *            defines how objects should be unfiled
       * @param continueOnFailure
       *            if {@code true} the repository tries to delete as many objects
       *            as possible; if {@code false} the repository stops at the
       *            first object that could not be deleted
       * 
       * @return a list of object IDs which failed to be deleted
       * 
       * @cmis 1.0
       */
      List<String> deleteTreebyPath(String parentPath, String name, boolean allVersions, UnfileObject unfile,
              boolean continueOnFailure);
  
      /**
       * Deletes a folder and all subfolders by path.
       * 
       * @param path
       *            the path of the folder
       * @param allVersions
       *            if this object is a document this parameter defines if only
       *            this version or all versions should be deleted
       * @param unfile
       *            defines how objects should be unfiled
       * @param continueOnFailure
       *            if {@code true} the repository tries to delete as many objects
       *            as possible; if {@code false} the repository stops at the
       *            first object that could not be deleted
       * 
       * @return a list of object IDs which failed to be deleted
       * 
       * @cmis 1.0
       */
      List<String> deleteTreebyPath(String path, boolean allVersions, UnfileObject unfile, boolean continueOnFailure);
  
      /**
       * Retrieves the main content stream of a document.
       * 
       * @param docId
       *            the ID of the document
       * 
       * @return the content stream or {@code null} if the document has no content
       *         stream
       * 
       * @cmis 1.0
       */
      ContentStream getContentStream(ObjectId docId);
  
      /**
       * Retrieves the content stream of a document.
       * 
       * @param docId
       *            the ID of the document
       * @param streamId
       *            the stream ID or {@code null} for the main stream
       * @param offset
       *            the offset of the stream or {@code null} to read the stream
       *            from the beginning
       * @param length
       *            the maximum length of the stream or {@code null} to read to
       *            the end of the stream
       * 
       * @return the content stream or {@code null} if the document has no content
       *         stream
       * 
       * @cmis 1.0
       */
      ContentStream getContentStream(ObjectId docId, String streamId, BigInteger offset, BigInteger length);
  
      /**
       * Retrieves the main content stream of a document.
       * 
       * @param path
       *            the path of the document
       * 
       * @return the content stream or {@code null} if the document has no content
       *         stream
       * 
       * @cmis 1.0
       */
      ContentStream getContentStreamByPath(String path);
  
      /**
       * Retrieves the content stream of a document.
       * 
       * @param path
       *            the path of the document
       * @param streamId
       *            the stream ID or {@code null} for the main stream
       * @param offset
       *            the offset of the stream or {@code null} to read the stream
       *            from the beginning
       * @param length
       *            the maximum length of the stream or {@code null} to read to
       *            the end of the stream
       * 
       * @return the content stream or {@code null} if the document has no content
       *         stream
       * 
       * @cmis 1.0
       */
      ContentStream getContentStreamByPath(String path, String streamId, BigInteger offset, BigInteger length);
  
      /**
       * Fetches the ACL of an object from the repository.
       * 
       * @param objectId
       *            the ID the object
       * @param onlyBasicPermissions
       *            if {@code true} the repository should express the ACL only
       *            with the basic permissions defined in the CMIS specification;
       *            if {@code false} the repository can express the ACL with basic
       *            and repository specific permissions
       * 
       * @return the ACL of the object
       * 
       * @cmis 1.0
       */
      Acl getAcl(ObjectId objectId, boolean onlyBasicPermissions);
  
      /**
       * Applies ACL changes to an object and dependent objects.
       * 
       * Only direct ACEs can be added and removed.
       * 
       * @param objectId
       *            the ID the object
       * @param addAces
       *            list of ACEs to be added or {@code null} if no ACEs should be
       *            added
       * @param removeAces
       *            list of ACEs to be removed or {@code null} if no ACEs should
       *            be removed
       * @param aclPropagation
       *            value that defines the propagation of the ACE changes;
       *            {@code null} is equal to
       *            {@link AclPropagation#REPOSITORYDETERMINED}
       * 
       * @return the new ACL of the object
       * 
       * @cmis 1.0
       */
      Acl applyAcl(ObjectId objectId, List<Ace> addAces, List<Ace> removeAces, AclPropagation aclPropagation);
  
      /**
       * Removes the direct ACEs of an object and sets the provided ACEs.
       * 
       * The changes are local to the given object and are not propagated to
       * dependent objects.
       * 
       * @param objectId
       *            the ID the object
       * @param aces
       *            list of ACEs to be set
       * 
       * @return the new ACL of the object
       * 
       * @cmis 1.0
       */
      Acl setAcl(ObjectId objectId, List<Ace> aces);
  
      /**
       * Applies a set of policies to an object.
       * 
       * This operation is not atomic. If it fails some policies might already be
       * applied.
       * 
       * @param objectId
       *            the ID the object
       * @param policyIds
       *            the IDs of the policies to be applied
       * 
       * @cmis 1.0
       */
      void applyPolicy(ObjectId objectId, ObjectId... policyIds);
  
      /**
       * Removes a set of policies from an object.
       * 
       * This operation is not atomic. If it fails some policies might already be
       * removed.
       * 
       * @param objectId
       *            the ID the object
       * @param policyIds
       *            the IDs of the policies to be removed
       * 
       * @cmis 1.0
       */
      void removePolicy(ObjectId objectId, ObjectId... policyIds);
  }
  