com.liferay.document.library.repository.cmis.internal.CMISRepository.java Source code

Java tutorial

Introduction

Here is the source code for com.liferay.document.library.repository.cmis.internal.CMISRepository.java

Source

/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

package com.liferay.document.library.repository.cmis.internal;

import com.liferay.document.library.kernel.exception.DuplicateFileEntryException;
import com.liferay.document.library.kernel.exception.DuplicateFolderNameException;
import com.liferay.document.library.kernel.exception.FileNameException;
import com.liferay.document.library.kernel.exception.NoSuchFileEntryException;
import com.liferay.document.library.kernel.exception.NoSuchFileVersionException;
import com.liferay.document.library.kernel.exception.NoSuchFolderException;
import com.liferay.document.library.kernel.model.DLFileEntryConstants;
import com.liferay.document.library.kernel.model.DLFolder;
import com.liferay.document.library.kernel.util.comparator.RepositoryModelCreateDateComparator;
import com.liferay.document.library.kernel.util.comparator.RepositoryModelModifiedDateComparator;
import com.liferay.document.library.kernel.util.comparator.RepositoryModelSizeComparator;
import com.liferay.document.library.kernel.util.comparator.RepositoryModelTitleComparator;
import com.liferay.document.library.repository.cmis.BaseCmisRepository;
import com.liferay.document.library.repository.cmis.CMISRepositoryHandler;
import com.liferay.document.library.repository.cmis.configuration.CMISRepositoryConfiguration;
import com.liferay.document.library.repository.cmis.internal.model.CMISFileEntry;
import com.liferay.document.library.repository.cmis.internal.model.CMISFileVersion;
import com.liferay.document.library.repository.cmis.internal.model.CMISFolder;
import com.liferay.document.library.repository.cmis.search.CMISSearchQueryBuilder;
import com.liferay.portal.kernel.dao.orm.QueryUtil;
import com.liferay.portal.kernel.exception.NoSuchRepositoryEntryException;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.language.LanguageUtil;
import com.liferay.portal.kernel.lock.Lock;
import com.liferay.portal.kernel.lock.LockManager;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.model.RepositoryEntry;
import com.liferay.portal.kernel.repository.RepositoryException;
import com.liferay.portal.kernel.repository.model.FileEntry;
import com.liferay.portal.kernel.repository.model.FileShortcut;
import com.liferay.portal.kernel.repository.model.FileVersion;
import com.liferay.portal.kernel.repository.model.Folder;
import com.liferay.portal.kernel.search.DocumentHelper;
import com.liferay.portal.kernel.search.DocumentImpl;
import com.liferay.portal.kernel.search.Field;
import com.liferay.portal.kernel.search.Hits;
import com.liferay.portal.kernel.search.HitsImpl;
import com.liferay.portal.kernel.search.Query;
import com.liferay.portal.kernel.search.QueryConfig;
import com.liferay.portal.kernel.search.SearchContext;
import com.liferay.portal.kernel.search.SearchException;
import com.liferay.portal.kernel.security.auth.PrincipalException;
import com.liferay.portal.kernel.service.RepositoryEntryLocalServiceUtil;
import com.liferay.portal.kernel.service.ServiceContext;
import com.liferay.portal.kernel.util.ArrayUtil;
import com.liferay.portal.kernel.util.ListUtil;
import com.liferay.portal.kernel.util.OrderByComparator;
import com.liferay.portal.kernel.util.StringBundler;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.Time;
import com.liferay.portal.kernel.util.Validator;

import java.io.InputStream;

import java.math.BigInteger;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.chemistry.opencmis.client.api.CmisObject;
import org.apache.chemistry.opencmis.client.api.Document;
import org.apache.chemistry.opencmis.client.api.FileableCmisObject;
import org.apache.chemistry.opencmis.client.api.ItemIterable;
import org.apache.chemistry.opencmis.client.api.ObjectId;
import org.apache.chemistry.opencmis.client.api.QueryResult;
import org.apache.chemistry.opencmis.client.api.Session;
import org.apache.chemistry.opencmis.client.runtime.ObjectIdImpl;
import org.apache.chemistry.opencmis.commons.PropertyIds;
import org.apache.chemistry.opencmis.commons.data.AllowableActions;
import org.apache.chemistry.opencmis.commons.data.ContentStream;
import org.apache.chemistry.opencmis.commons.data.PropertyData;
import org.apache.chemistry.opencmis.commons.data.RepositoryCapabilities;
import org.apache.chemistry.opencmis.commons.data.RepositoryInfo;
import org.apache.chemistry.opencmis.commons.enums.Action;
import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
import org.apache.chemistry.opencmis.commons.enums.CapabilityQuery;
import org.apache.chemistry.opencmis.commons.enums.UnfileObject;
import org.apache.chemistry.opencmis.commons.enums.VersioningState;
import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisPermissionDeniedException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
import org.apache.chemistry.opencmis.commons.impl.Base64;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.ContentStreamImpl;

/**
 * CMIS does not provide vendor neutral support for workflow, metadata, tags,
 * categories, etc. They will be ignored in this implementation.
 *
 * @author Alexander Chow
 * @see    <a href="http://wiki.oasis-open.org/cmis/Candidate%20v2%20topics">
 *         Candidate v2 topics</a>
 * @see    <a href="http://wiki.oasis-open.org/cmis/Mixin_Proposal">Mixin /
 *         Aspect Support</a>
 * @see    <a
 *         href="http://www.oasis-open.org/committees/document.php?document_id=39631">
 *         CMIS Type Mutability proposal</a>
 */
public class CMISRepository extends BaseCmisRepository {

    public CMISRepository(CMISRepositoryConfiguration cmisRepositoryConfiguration,
            CMISRepositoryHandler cmisRepositoryHandler, CMISSearchQueryBuilder cmisSearchQueryBuilder,
            CMISSessionCache cmisSessionCache, LockManager lockManager) {

        _cmisRepositoryConfiguration = cmisRepositoryConfiguration;
        _cmisRepositoryHandler = cmisRepositoryHandler;
        _cmisSearchQueryBuilder = cmisSearchQueryBuilder;
        _cmisSessionCache = cmisSessionCache;
        _lockManager = lockManager;
    }

    @Override
    public FileEntry addFileEntry(long userId, long folderId, String sourceFileName, String mimeType, String title,
            String description, String changeLog, InputStream is, long size, ServiceContext serviceContext)
            throws PortalException {

        if (Validator.isNull(title)) {
            if (size == 0) {
                throw new FileNameException("Title is null");
            } else {
                title = sourceFileName;
            }
        }

        try {
            Session session = getSession();

            validateTitle(session, folderId, title);

            org.apache.chemistry.opencmis.client.api.Folder cmisFolder = getCmisFolder(session, folderId);

            Map<String, Object> properties = new HashMap<>();

            properties.put(PropertyIds.NAME, title);
            properties.put(PropertyIds.OBJECT_TYPE_ID, BaseTypeId.CMIS_DOCUMENT.value());

            ContentStream contentStream = new ContentStreamImpl(title, BigInteger.valueOf(size), mimeType, is);

            Document document = null;

            if (_cmisRepositoryDetector.isNuxeo5_5OrHigher()) {
                document = cmisFolder.createDocument(properties, contentStream, VersioningState.NONE);

                document.checkIn(true, Collections.<String, Object>emptyMap(), null, StringPool.BLANK);
            } else {
                document = cmisFolder.createDocument(properties, contentStream, null);
            }

            return toFileEntry(document);
        } catch (PortalException | SystemException e) {
            throw e;
        } catch (Exception e) {
            processException(e);

            throw new RepositoryException(e);
        }
    }

    @Override
    public FileShortcut addFileShortcut(long userId, long folderId, long toFileEntryId,
            ServiceContext serviceContext) {

        throw new UnsupportedOperationException();
    }

    @Override
    public Folder addFolder(long userId, long parentFolderId, String name, String description,
            ServiceContext serviceContext) throws PortalException {

        try {
            Session session = getSession();

            validateTitle(session, parentFolderId, name);

            org.apache.chemistry.opencmis.client.api.Folder cmisFolder = getCmisFolder(session, parentFolderId);

            Map<String, Object> properties = new HashMap<>();

            properties.put(PropertyIds.NAME, name);
            properties.put(PropertyIds.OBJECT_TYPE_ID, BaseTypeId.CMIS_FOLDER.value());

            return toFolder(cmisFolder.createFolder(properties));
        } catch (PortalException | SystemException e) {
            throw e;
        } catch (Exception e) {
            processException(e);

            throw new RepositoryException(e);
        }
    }

    @Override
    public FileVersion cancelCheckOut(long fileEntryId) throws PortalException {
        Document draftDocument = null;

        try {
            Session session = getSession();

            String versionSeriesId = toFileEntryId(fileEntryId);

            Document document = (Document) session.getObject(versionSeriesId);

            document.refresh();

            String versionSeriesCheckedOutId = document.getVersionSeriesCheckedOutId();

            if (Validator.isNotNull(versionSeriesCheckedOutId)) {
                draftDocument = (Document) session.getObject(versionSeriesCheckedOutId);

                draftDocument.cancelCheckOut();

                document = (Document) session.getObject(versionSeriesId);

                document.refresh();
            }
        } catch (Exception e) {
            _log.error("Unable to cancel checkout for file entry with {fileEntryId=" + fileEntryId + "}", e);
        }

        if (draftDocument != null) {
            return toFileVersion(null, draftDocument);
        }

        return null;
    }

    @Override
    public void checkInFileEntry(long userId, long fileEntryId, boolean major, String changeLog,
            ServiceContext serviceContext) {

        try {
            clearManualCheckInRequired(fileEntryId, serviceContext);

            Session session = getSession();

            String versionSeriesId = toFileEntryId(fileEntryId);

            Document document = (Document) session.getObject(versionSeriesId);

            document.refresh();

            String versionSeriesCheckedOutId = document.getVersionSeriesCheckedOutId();

            if (Validator.isNotNull(versionSeriesCheckedOutId)) {
                if (!isSupportsMinorVersions()) {
                    major = true;
                }

                document = (Document) session.getObject(versionSeriesCheckedOutId);

                document.checkIn(major, null, null, changeLog);

                document = (Document) session.getObject(versionSeriesId);

                document.refresh();
            }
        } catch (Exception e) {
            _log.error("Unable to check in file entry with {fileEntryId=" + fileEntryId + "}", e);
        }
    }

    @Override
    public void checkInFileEntry(long userId, long fileEntryId, String lockUuid, ServiceContext serviceContext) {

        checkInFileEntry(userId, fileEntryId, false, StringPool.BLANK, serviceContext);
    }

    @Override
    public FileEntry checkOutFileEntry(long fileEntryId, ServiceContext serviceContext) throws PortalException {

        try {
            setManualCheckInRequired(fileEntryId, serviceContext);

            Session session = getSession();

            String versionSeriesId = toFileEntryId(fileEntryId);

            Document document = (Document) session.getObject(versionSeriesId);

            document.refresh();

            document.checkOut();

            document = (Document) session.getObject(versionSeriesId);

            document.refresh();
        } catch (Exception e) {
            _log.error("Unable checkout file entry with {fileEntryId=" + fileEntryId + "}", e);
        }

        return getFileEntry(fileEntryId);
    }

    @Override
    public FileEntry checkOutFileEntry(long fileEntryId, String owner, long expirationTime,
            ServiceContext serviceContext) {

        throw new UnsupportedOperationException();
    }

    @Override
    public FileEntry copyFileEntry(long userId, long groupId, long fileEntryId, long destFolderId,
            ServiceContext serviceContext) throws PortalException {

        try {
            Session session = getSession();

            Document document = getDocument(session, fileEntryId);

            validateTitle(session, destFolderId, document.getName());

            String destFolderObjectId = toFolderId(session, destFolderId);

            Document newDocument = document.copy(new ObjectIdImpl(destFolderObjectId));

            return toFileEntry(newDocument);
        } catch (CmisObjectNotFoundException confe) {
            throw new NoSuchFolderException("No CMIS folder with {folderId=" + destFolderId + "}", confe);
        } catch (PortalException | SystemException e) {
            throw e;
        } catch (Exception e) {
            processException(e);

            throw new RepositoryException(e);
        }
    }

    @Override
    public void deleteFileEntry(long fileEntryId) throws PortalException {
        try {
            Session session = getSession();

            Document document = getDocument(session, fileEntryId);

            deleteMappedFileEntry(document);

            document.deleteAllVersions();
        } catch (PortalException | SystemException e) {
            throw e;
        } catch (Exception e) {
            processException(e);

            throw new RepositoryException(e);
        }
    }

    @Override
    public void deleteFileShortcut(long fileShortcutId) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void deleteFileShortcuts(long toFileEntryId) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void deleteFolder(long folderId) throws PortalException {
        try {
            Session session = getSession();

            org.apache.chemistry.opencmis.client.api.Folder cmisFolder = getCmisFolder(session, folderId);

            deleteMappedFolder(cmisFolder);

            cmisFolder.deleteTree(true, UnfileObject.DELETE, false);
        } catch (PortalException | SystemException e) {
            throw e;
        } catch (Exception e) {
            processException(e);

            throw new RepositoryException(e);
        }
    }

    @Override
    public List<FileEntry> getFileEntries(long folderId, int status, int start, int end,
            OrderByComparator<FileEntry> obc) {

        return getFileEntries(folderId, start, end, obc);
    }

    @Override
    public List<FileEntry> getFileEntries(long folderId, int start, int end, OrderByComparator<FileEntry> obc) {

        List<FileEntry> fileEntries = getFileEntries(folderId);

        return subList(fileEntries, start, end, obc);
    }

    @Override
    public List<FileEntry> getFileEntries(long folderId, long fileEntryTypeId, int start, int end,
            OrderByComparator<FileEntry> obc) {

        return new ArrayList<>();
    }

    @Override
    public List<FileEntry> getFileEntries(long folderId, String[] mimeTypes, int start, int end,
            OrderByComparator<FileEntry> obc) throws PortalException {

        List<FileEntry> fileEntries = _cmisModelCache.getFileEntries(folderId);

        if ((fileEntries == null) || (mimeTypes != null)) {
            fileEntries = new ArrayList<>();

            List<String> documentIds = getDocumentIds(getSession(), folderId, mimeTypes);

            for (String documentId : documentIds) {
                FileEntry fileEntry = toFileEntry(documentId);

                fileEntries.add(fileEntry);
            }

            if (mimeTypes == null) {
                _cmisModelCache.putFileEntries(folderId, fileEntries);
            }
        }

        return subList(fileEntries, start, end, obc);
    }

    @Override
    public int getFileEntriesCount(long folderId) {
        List<FileEntry> fileEntries = getFileEntries(folderId);

        return fileEntries.size();
    }

    @Override
    public int getFileEntriesCount(long folderId, int status) {
        List<FileEntry> fileEntries = getFileEntries(folderId);

        return fileEntries.size();
    }

    @Override
    public int getFileEntriesCount(long folderId, long fileEntryTypeId) {
        List<FileEntry> fileEntries = getFileEntries(folderId, fileEntryTypeId);

        return fileEntries.size();
    }

    @Override
    public int getFileEntriesCount(long folderId, String[] mimeTypes) throws PortalException {

        Session session = getSession();

        List<String> documentIds = getDocumentIds(session, folderId, mimeTypes);

        return documentIds.size();
    }

    @Override
    public FileEntry getFileEntry(long fileEntryId) throws PortalException {
        try {
            FileEntry fileEntry = _cmisModelCache.getFileEntry(fileEntryId);

            if (fileEntry == null) {
                Session session = getSession();

                Document document = getDocument(session, fileEntryId);

                fileEntry = toFileEntry(document);

                _cmisModelCache.putFileEntry(fileEntry);
            }

            return fileEntry;
        } catch (PortalException | SystemException e) {
            throw e;
        } catch (Exception e) {
            processException(e);

            throw new RepositoryException(e);
        }
    }

    @Override
    public FileEntry getFileEntry(long folderId, String title) throws PortalException {

        try {
            Session session = getSession();

            String objectId = getObjectId(session, folderId, true, title);

            if (objectId != null) {
                CmisObject cmisObject = session.getObject(objectId);

                Document document = (Document) cmisObject;

                return toFileEntry(document);
            }
        } catch (CmisObjectNotFoundException confe) {
            throw new NoSuchFileEntryException(
                    "No CMIS file entry with {folderId=" + folderId + ", title=" + title + "}", confe);
        } catch (PortalException | SystemException e) {
            throw e;
        } catch (Exception e) {
            processException(e);

            throw new RepositoryException(e);
        }

        throw new NoSuchFileEntryException(
                "No CMIS file entry with {folderId=" + folderId + ", title=" + title + "}");
    }

    @Override
    public FileEntry getFileEntryByUuid(String uuid) throws PortalException {
        try {
            Session session = getSession();

            RepositoryEntry repositoryEntry = repositoryEntryLocalService.getRepositoryEntry(uuid, getGroupId());

            String objectId = repositoryEntry.getMappedId();

            return toFileEntry((Document) session.getObject(objectId));
        } catch (CmisObjectNotFoundException confe) {
            throw new NoSuchFileEntryException("No CMIS file entry with {uuid=" + uuid + "}", confe);
        } catch (NoSuchRepositoryEntryException nsree) {
            throw new NoSuchFileEntryException(nsree);
        } catch (SystemException se) {
            throw se;
        } catch (Exception e) {
            processException(e);

            throw new RepositoryException(e);
        }
    }

    @Override
    public FileShortcut getFileShortcut(long fileShortcutId) {
        throw new UnsupportedOperationException();
    }

    @Override
    public FileVersion getFileVersion(long fileVersionId) throws PortalException {

        try {
            Session session = getSession();

            return getFileVersion(session, null, fileVersionId);
        } catch (PortalException | SystemException e) {
            throw e;
        } catch (Exception e) {
            processException(e);

            throw new RepositoryException(e);
        }
    }

    @Override
    public Folder getFolder(long folderId) throws PortalException {
        try {
            Session session = getSession();

            return getFolder(session, folderId);
        } catch (PortalException | SystemException e) {
            throw e;
        } catch (Exception e) {
            processException(e);

            throw new RepositoryException(e);
        }
    }

    @Override
    public Folder getFolder(long parentFolderId, String name) throws PortalException {

        try {
            Session session = getSession();

            String objectId = getObjectId(session, parentFolderId, false, name);

            if (objectId != null) {
                CmisObject cmisObject = session.getObject(objectId);

                return toFolder((org.apache.chemistry.opencmis.client.api.Folder) cmisObject);
            }
        } catch (CmisObjectNotFoundException confe) {
            throw new NoSuchFolderException(
                    "No CMIS folder with {parentFolderId=" + parentFolderId + ", name=" + name + "}", confe);
        } catch (PortalException | SystemException e) {
            throw e;
        } catch (Exception e) {
            processException(e);

            throw new RepositoryException(e);
        }

        throw new NoSuchFolderException(
                "No CMIS folder with {parentFolderId=" + parentFolderId + ", name=" + name + "}");
    }

    @Override
    public List<Folder> getFolders(long parentFolderId, boolean includeMountfolders, int start, int end,
            OrderByComparator<Folder> obc) throws PortalException {

        List<Folder> folders = getFolders(parentFolderId);

        return subList(folders, start, end, obc);
    }

    @Override
    public List<Object> getFoldersAndFileEntries(long folderId, int start, int end, OrderByComparator<?> obc) {

        List<Object> foldersAndFileEntries = getFoldersAndFileEntries(folderId);

        return subList(foldersAndFileEntries, start, end, (OrderByComparator<Object>) obc);
    }

    @Override
    public List<Object> getFoldersAndFileEntries(long folderId, String[] mimeTypes, int start, int end,
            OrderByComparator<?> obc) throws PortalException {

        List<Object> foldersAndFileEntries = _cmisModelCache.getFoldersAndFileEntries(folderId);

        if ((foldersAndFileEntries == null) || (mimeTypes != null)) {
            foldersAndFileEntries = new ArrayList<>();

            foldersAndFileEntries.addAll(getFolders(folderId));

            List<FileEntry> fileEntries = getFileEntries(folderId, mimeTypes, QueryUtil.ALL_POS, QueryUtil.ALL_POS,
                    null);

            foldersAndFileEntries.addAll(fileEntries);

            if (mimeTypes == null) {
                _cmisModelCache.putFoldersAndFileEntries(folderId, foldersAndFileEntries);
            }
        }

        return subList(foldersAndFileEntries, start, end, (OrderByComparator<Object>) obc);
    }

    @Override
    public int getFoldersAndFileEntriesCount(long folderId) {
        List<Object> foldersAndFileEntries = getFoldersAndFileEntries(folderId);

        return foldersAndFileEntries.size();
    }

    @Override
    public int getFoldersAndFileEntriesCount(long folderId, String[] mimeTypes) throws PortalException {

        if (ArrayUtil.isNotEmpty(mimeTypes)) {
            List<Folder> folders = getFolders(folderId);

            Session session = getSession();

            List<String> documentIds = getDocumentIds(session, folderId, mimeTypes);

            return folders.size() + documentIds.size();
        }

        List<Object> foldersAndFileEntries = getFoldersAndFileEntries(folderId);

        return foldersAndFileEntries.size();
    }

    @Override
    public int getFoldersCount(long parentFolderId, boolean includeMountfolders) throws PortalException {

        List<Folder> folders = getFolders(parentFolderId);

        return folders.size();
    }

    @Override
    public int getFoldersFileEntriesCount(List<Long> folderIds, int status) {
        int count = 0;

        for (long folderId : folderIds) {
            List<FileEntry> fileEntries = getFileEntries(folderId);

            count += fileEntries.size();
        }

        return count;
    }

    @Override
    public String getLatestVersionId(String objectId) {
        try {
            Session session = getSession();

            Document document = (Document) session.getObject(objectId);

            List<Document> documentVersions = document.getAllVersions();

            document = documentVersions.get(0);

            return document.getId();
        } catch (Exception e) {
            throw new RepositoryException(e);
        }
    }

    @Override
    public List<Folder> getMountFolders(long parentFolderId, int start, int end, OrderByComparator<Folder> obc) {

        return new ArrayList<>();
    }

    @Override
    public int getMountFoldersCount(long parentFolderId) {
        return 0;
    }

    @Override
    public String getObjectName(String objectId) throws PortalException {
        Session session = getSession();

        CmisObject cmisObject = session.getObject(objectId);

        return cmisObject.getName();
    }

    @Override
    public List<String> getObjectPaths(String objectId) throws PortalException {
        Session session = getSession();

        CmisObject cmisObject = session.getObject(objectId);

        if (cmisObject instanceof FileableCmisObject) {
            FileableCmisObject fileableCmisObject = (FileableCmisObject) cmisObject;

            return fileableCmisObject.getPaths();
        }

        throw new RepositoryException("CMIS object is unfileable for id " + objectId);
    }

    public Session getSession() throws PortalException {
        Session session = _cmisSessionCache.get(_sessionKey);

        if (session == null) {
            SessionImpl sessionImpl = (SessionImpl) _cmisRepositoryHandler.getSession();

            session = sessionImpl.getSession();

            _cmisSessionCache.put(_sessionKey, session);
        }

        if (_cmisRepositoryDetector == null) {
            RepositoryInfo repositoryInfo = session.getRepositoryInfo();

            _cmisRepositoryDetector = new CMISRepositoryDetector(repositoryInfo);
        }

        return session;
    }

    @Override
    public void getSubfolderIds(List<Long> folderIds, long folderId) {
        try {
            List<Folder> subfolders = getFolders(folderId, false, QueryUtil.ALL_POS, QueryUtil.ALL_POS, null);

            getSubfolderIds(folderIds, subfolders, true);
        } catch (SystemException se) {
            throw se;
        } catch (Exception e) {
            throw new RepositoryException(e);
        }
    }

    @Override
    public List<Long> getSubfolderIds(long folderId, boolean recurse) {
        try {
            List<Long> subfolderIds = new ArrayList<>();

            List<Folder> subfolders = getFolders(folderId, false, QueryUtil.ALL_POS, QueryUtil.ALL_POS, null);

            getSubfolderIds(subfolderIds, subfolders, recurse);

            return subfolderIds;
        } catch (SystemException se) {
            throw se;
        } catch (Exception e) {
            throw new RepositoryException(e);
        }
    }

    /**
     * @deprecated As of 2.0.0
     */
    @Deprecated
    @Override
    public String[] getSupportedConfigurations() {
        return _cmisRepositoryHandler.getSupportedConfigurations();
    }

    /**
     * @deprecated As of 2.0.0
     */
    @Deprecated
    @Override
    public String[][] getSupportedParameters() {
        return _cmisRepositoryHandler.getSupportedParameters();
    }

    @Override
    public void initRepository() throws PortalException {
        try {
            _sessionKey = Session.class.getName().concat(StringPool.POUND)
                    .concat(String.valueOf(getRepositoryId()));

            Session session = getSession();

            session.getRepositoryInfo();
        } catch (PortalException | SystemException e) {
            throw e;
        } catch (Exception e) {
            processException(e);

            throw new RepositoryException("Unable to initialize CMIS session for repository with "
                    + "{repositoryId=" + getRepositoryId() + "}", e);
        }
    }

    @Override
    public boolean isCancelCheckOutAllowable(String objectId) throws PortalException {

        return isActionAllowable(objectId, Action.CAN_CANCEL_CHECK_OUT);
    }

    @Override
    public boolean isCheckInAllowable(String objectId) throws PortalException {
        return isActionAllowable(objectId, Action.CAN_CHECK_IN);
    }

    @Override
    public boolean isCheckOutAllowable(String objectId) throws PortalException {
        return isActionAllowable(objectId, Action.CAN_CHECK_OUT);
    }

    public boolean isDocumentRetrievableByVersionSeriesId() {
        return _cmisRepositoryHandler.isDocumentRetrievableByVersionSeriesId();
    }

    public boolean isRefreshBeforePermissionCheck() {
        return _cmisRepositoryHandler.isRefreshBeforePermissionCheck();
    }

    @Override
    public boolean isSupportsMinorVersions() throws PortalException {
        try {
            Session session = getSession();

            RepositoryInfo repositoryInfo = session.getRepositoryInfo();

            String productName = repositoryInfo.getProductName();

            return _cmisRepositoryHandler.isSupportsMinorVersions(productName);
        } catch (PortalException | SystemException e) {
            throw e;
        } catch (Exception e) {
            processException(e);

            throw new RepositoryException(e);
        }
    }

    @Override
    public Lock lockFolder(long folderId) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Lock lockFolder(long folderId, String owner, boolean inheritable, long expirationTime) {

        throw new UnsupportedOperationException();
    }

    @Override
    public FileEntry moveFileEntry(long userId, long fileEntryId, long newFolderId, ServiceContext serviceContext)
            throws PortalException {

        try {
            Session session = getSession();

            String newFolderObjectId = toFolderId(session, newFolderId);

            Document document = getDocument(session, fileEntryId);

            validateTitle(session, newFolderId, document.getName());

            List<org.apache.chemistry.opencmis.client.api.Folder> parentFolders = document.getParents();

            org.apache.chemistry.opencmis.client.api.Folder oldFolder = parentFolders.get(0);

            String oldFolderObjectId = oldFolder.getId();

            if (oldFolderObjectId.equals(newFolderObjectId)) {
                return toFileEntry(document);
            }

            document = (Document) document.move(new ObjectIdImpl(oldFolderObjectId),
                    new ObjectIdImpl(newFolderObjectId));

            String versionSeriesId = toFileEntryId(fileEntryId);

            String newObjectId = document.getVersionSeriesId();

            if (!versionSeriesId.equals(newObjectId)) {
                document = (Document) session.getObject(newObjectId);

                updateMappedId(fileEntryId, document.getVersionSeriesId());
            }

            return toFileEntry(document);
        } catch (CmisObjectNotFoundException confe) {
            throw new NoSuchFolderException("No CMIS folder with {folderId=" + newFolderId + "}", confe);
        } catch (PortalException | SystemException e) {
            throw e;
        } catch (Exception e) {
            processException(e);

            throw new RepositoryException(e);
        }
    }

    @Override
    public Folder moveFolder(long userId, long folderId, long parentFolderId, ServiceContext serviceContext)
            throws PortalException {

        try {
            Session session = getSession();

            org.apache.chemistry.opencmis.client.api.Folder cmisFolder = getCmisFolder(session, folderId);

            validateTitle(session, parentFolderId, cmisFolder.getName());

            org.apache.chemistry.opencmis.client.api.Folder parentCmisFolder = cmisFolder.getFolderParent();

            if (parentCmisFolder == null) {
                throw new RepositoryException("Unable to move CMIS root folder with {folderId=" + folderId + "}");
            }

            String objectId = toFolderId(session, folderId);

            String sourceFolderId = parentCmisFolder.getId();

            String targetFolderId = toFolderId(session, parentFolderId);

            if (!sourceFolderId.equals(targetFolderId) && !targetFolderId.equals(objectId)) {

                cmisFolder = (org.apache.chemistry.opencmis.client.api.Folder) cmisFolder
                        .move(new ObjectIdImpl(sourceFolderId), new ObjectIdImpl(targetFolderId));
            }

            return toFolder(cmisFolder);
        } catch (CmisObjectNotFoundException confe) {
            throw new NoSuchFolderException("No CMIS folder with {folderId=" + parentFolderId + "}", confe);
        } catch (PortalException | SystemException e) {
            throw e;
        } catch (Exception e) {
            processException(e);

            throw new RepositoryException(e);
        }
    }

    @Override
    public Lock refreshFileEntryLock(String lockUuid, long companyId, long expirationTime) {

        throw new UnsupportedOperationException();
    }

    @Override
    public Lock refreshFolderLock(String lockUuid, long companyId, long expirationTime) {

        throw new UnsupportedOperationException();
    }

    @Override
    public void revertFileEntry(long userId, long fileEntryId, String version, ServiceContext serviceContext)
            throws PortalException {

        try {
            Session session = getSession();

            Document document = getDocument(session, fileEntryId);

            Document oldVersion = null;

            List<Document> documentVersions = document.getAllVersions();

            for (Document currentVersion : documentVersions) {
                String currentVersionLabel = currentVersion.getVersionLabel();

                if (Validator.isNull(currentVersionLabel)) {
                    currentVersionLabel = DLFileEntryConstants.VERSION_DEFAULT;
                }

                if (currentVersionLabel.equals(version)) {
                    oldVersion = currentVersion;

                    break;
                }
            }

            String mimeType = oldVersion.getContentStreamMimeType();
            String changeLog = LanguageUtil.format(serviceContext.getLocale(), "reverted-to-x", version, false);
            String title = oldVersion.getName();
            ContentStream contentStream = oldVersion.getContentStream();

            updateFileEntry(userId, fileEntryId, contentStream.getFileName(), mimeType, title, StringPool.BLANK,
                    changeLog, true, contentStream.getStream(), contentStream.getLength(), serviceContext);
        } catch (PortalException | SystemException e) {
            throw e;
        } catch (Exception e) {
            processException(e);

            throw new RepositoryException(e);
        }
    }

    @Override
    public Hits search(long creatorUserId, int status, int start, int end) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Hits search(long creatorUserId, long folderId, String[] mimeTypes, int status, int start, int end) {

        throw new UnsupportedOperationException();
    }

    @Override
    public Hits search(SearchContext searchContext, Query query) throws SearchException {

        try {
            QueryConfig queryConfig = searchContext.getQueryConfig();

            queryConfig.setScoreEnabled(false);

            return doSearch(searchContext, query);
        } catch (Exception e) {
            throw new SearchException(e);
        }
    }

    public FileEntry toFileEntry(Document document) throws PortalException {
        return toFileEntry(document, false);
    }

    @Override
    public FileEntry toFileEntry(String objectId) throws PortalException {
        return toFileEntry(objectId, false);
    }

    public FileVersion toFileVersion(FileEntry fileEntry, Document version) throws PortalException {

        RepositoryEntry repositoryEntry = getRepositoryEntry(version.getId());

        return new CMISFileVersion(this, fileEntry, repositoryEntry.getUuid(),
                repositoryEntry.getRepositoryEntryId(), version);
    }

    public Folder toFolder(org.apache.chemistry.opencmis.client.api.Folder cmisFolder) throws PortalException {

        RepositoryEntry repositoryEntry = getRepositoryEntry(cmisFolder.getId());

        return new CMISFolder(this, repositoryEntry.getUuid(), repositoryEntry.getRepositoryEntryId(), cmisFolder);
    }

    @Override
    public Folder toFolder(String objectId) throws PortalException {
        try {
            Session session = getSession();

            org.apache.chemistry.opencmis.client.api.Folder cmisFolder = (org.apache.chemistry.opencmis.client.api.Folder) session
                    .getObject(objectId);

            return toFolder(cmisFolder);
        } catch (CmisObjectNotFoundException confe) {
            throw new NoSuchFolderException("No CMIS folder with {objectId=" + objectId + "}", confe);
        } catch (SystemException se) {
            throw se;
        } catch (Exception e) {
            processException(e);

            throw new RepositoryException(e);
        }
    }

    @Override
    public void unlockFolder(long folderId, String lockUuid) {
        throw new UnsupportedOperationException();
    }

    @Override
    public FileEntry updateFileEntry(long userId, long fileEntryId, String sourceFileName, String mimeType,
            String title, String description, String changeLog, boolean majorVersion, InputStream is, long size,
            ServiceContext serviceContext) throws PortalException {

        Document document = null;

        ObjectId checkOutDocumentObjectId = null;

        try {
            Session session = getSession();

            document = getDocument(session, fileEntryId);

            String versionSeriesCheckedOutId = document.getVersionSeriesCheckedOutId();

            if (Validator.isNotNull(versionSeriesCheckedOutId)) {
                document = (Document) session.getObject(versionSeriesCheckedOutId);

                document.refresh();
            }

            String currentTitle = document.getName();

            AllowableActions allowableActions = document.getAllowableActions();

            Set<Action> allowableActionsSet = allowableActions.getAllowableActions();

            if (allowableActionsSet.contains(Action.CAN_CHECK_OUT)) {
                checkOutDocumentObjectId = document.checkOut();

                document = (Document) session.getObject(checkOutDocumentObjectId);
            }

            Map<String, Object> properties = null;

            ContentStream contentStream = null;

            if (Validator.isNotNull(title) && !title.equals(currentTitle)) {
                properties = new HashMap<>();

                properties.put(PropertyIds.NAME, title);
            }

            if (is != null) {
                contentStream = new ContentStreamImpl(sourceFileName, BigInteger.valueOf(size), mimeType, is);
            }

            checkUpdatable(allowableActionsSet, properties, contentStream);

            if (checkOutDocumentObjectId != null) {
                if (!isSupportsMinorVersions()) {
                    majorVersion = true;
                }

                document.checkIn(majorVersion, properties, contentStream, changeLog);

                checkOutDocumentObjectId = null;
            } else {
                if (properties != null) {
                    document = (Document) document.updateProperties(properties);
                }

                if (contentStream != null) {
                    document.setContentStream(contentStream, true, false);
                }
            }

            String versionSeriesId = toFileEntryId(fileEntryId);

            document = (Document) session.getObject(versionSeriesId);

            return toFileEntry(document);
        } catch (PortalException | SystemException e) {
            throw e;
        } catch (Exception e) {
            processException(e);

            throw new RepositoryException(e);
        } finally {
            if (checkOutDocumentObjectId != null) {
                document.cancelCheckOut();
            }
        }
    }

    @Override
    public FileEntry updateFileEntry(String objectId, String mimeType, Map<String, Object> properties,
            InputStream is, String sourceFileName, long size, ServiceContext serviceContext)
            throws PortalException {

        try {
            Session session = getSession();

            Document document = (Document) session.getObject(objectId);

            AllowableActions allowableActions = document.getAllowableActions();

            Set<Action> allowableActionsSet = allowableActions.getAllowableActions();

            ContentStream contentStream = null;

            if (is != null) {
                is = new Base64.InputStream(is, Base64.ENCODE);

                contentStream = new ContentStreamImpl(sourceFileName, BigInteger.valueOf(size), mimeType, is);
            }

            checkUpdatable(allowableActionsSet, properties, contentStream);

            if (properties != null) {
                document = (Document) document.updateProperties(properties);
            }

            if (contentStream != null) {
                document.setContentStream(contentStream, true, false);
            }

            return toFileEntry(document);
        } catch (PortalException | SystemException e) {
            throw e;
        } catch (Exception e) {
            processException(e);

            throw new RepositoryException(e);
        }
    }

    @Override
    public FileShortcut updateFileShortcut(long userId, long fileShortcutId, long folderId, long toFileEntryId,
            ServiceContext serviceContext) {

        throw new UnsupportedOperationException();
    }

    @Override
    public void updateFileShortcuts(long oldToFileEntryId, long newToFileEntryId) {

        throw new UnsupportedOperationException();
    }

    @Override
    public Folder updateFolder(long folderId, String name, String description, ServiceContext serviceContext)
            throws PortalException {

        try {
            Session session = getSession();

            String objectId = toFolderId(session, folderId);

            org.apache.chemistry.opencmis.client.api.Folder cmisFolder = (org.apache.chemistry.opencmis.client.api.Folder) session
                    .getObject(objectId);

            String currentTitle = cmisFolder.getName();

            Map<String, Object> properties = new HashMap<>();

            if (Validator.isNotNull(name) && !name.equals(currentTitle)) {
                properties.put(PropertyIds.NAME, name);
            }

            ObjectId cmisFolderObjectId = cmisFolder.updateProperties(properties, true);

            String newObjectId = cmisFolderObjectId.getId();

            if (!objectId.equals(newObjectId)) {
                cmisFolder = (org.apache.chemistry.opencmis.client.api.Folder) session.getObject(newObjectId);

                updateMappedId(folderId, newObjectId);
            }

            return toFolder(cmisFolder);
        } catch (CmisObjectNotFoundException confe) {
            throw new NoSuchFolderException("No CMIS folder with {folderId=" + folderId + "}", confe);
        } catch (PortalException | SystemException e) {
            throw e;
        } catch (Exception e) {
            processException(e);

            throw new RepositoryException(e);
        }
    }

    @Override
    public boolean verifyFileEntryCheckOut(long fileEntryId, String lockUuid) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean verifyInheritableLock(long folderId, String lockUuid) {
        throw new UnsupportedOperationException();
    }

    protected void cacheFoldersAndFileEntries(long folderId) {
        try {
            if (_cmisModelCache.getFoldersAndFileEntries(folderId) != null) {
                return;
            }

            List<Object> foldersAndFileEntries = new ArrayList<>();
            List<Folder> folders = new ArrayList<>();
            List<FileEntry> fileEntries = new ArrayList<>();

            Session session = getSession();

            org.apache.chemistry.opencmis.client.api.Folder cmisParentFolder = getCmisFolder(session, folderId);

            Folder parentFolder = toFolder(cmisParentFolder);

            ItemIterable<CmisObject> cmisObjects = cmisParentFolder.getChildren();

            for (CmisObject cmisObject : cmisObjects) {
                if (cmisObject instanceof org.apache.chemistry.opencmis.client.api.Folder) {

                    CMISFolder cmisFolder = (CMISFolder) toFolder(
                            (org.apache.chemistry.opencmis.client.api.Folder) cmisObject);

                    cmisFolder.setParentFolder(parentFolder);

                    foldersAndFileEntries.add(cmisFolder);
                    folders.add(cmisFolder);

                    _cmisModelCache.putFolder(cmisFolder);
                } else if (cmisObject instanceof Document) {
                    CMISFileEntry cmisFileEntry = (CMISFileEntry) toFileEntry((Document) cmisObject);

                    cmisFileEntry.setParentFolder(parentFolder);

                    foldersAndFileEntries.add(cmisFileEntry);
                    fileEntries.add(cmisFileEntry);

                    _cmisModelCache.putFileEntry(cmisFileEntry);
                }
            }

            _cmisModelCache.putFoldersAndFileEntries(folderId, foldersAndFileEntries);

            _cmisModelCache.putFolders(folderId, folders);

            _cmisModelCache.putFileEntries(folderId, fileEntries);
        } catch (SystemException se) {
            throw se;
        } catch (Exception e) {
            throw new RepositoryException(e);
        }
    }

    protected void checkUpdatable(Set<Action> allowableActionsSet, Map<String, Object> properties,
            ContentStream contentStream) throws PrincipalException {

        if (properties != null) {
            if (!allowableActionsSet.contains(Action.CAN_UPDATE_PROPERTIES)) {
                throw new PrincipalException.MustHavePermission(0, Action.CAN_UPDATE_PROPERTIES.toString());
            }
        }

        if (contentStream != null) {
            if (!allowableActionsSet.contains(Action.CAN_SET_CONTENT_STREAM)) {
                throw new PrincipalException.MustHavePermission(0, Action.CAN_SET_CONTENT_STREAM.toString());
            }
        }
    }

    protected void deleteMappedFileEntry(Document document) throws PortalException {

        if (_cmisRepositoryConfiguration.deleteDepth() == _DELETE_NONE) {
            return;
        }

        List<Document> documentVersions = document.getAllVersions();

        List<String> mappedIds = new ArrayList<>(documentVersions.size() + 1);

        for (Document version : documentVersions) {
            mappedIds.add(version.getId());
        }

        mappedIds.add(document.getId());

        repositoryEntryLocalService.deleteRepositoryEntries(getRepositoryId(), mappedIds);
    }

    protected void deleteMappedFolder(org.apache.chemistry.opencmis.client.api.Folder cmisFolder)
            throws PortalException {

        if (_cmisRepositoryConfiguration.deleteDepth() == _DELETE_NONE) {
            return;
        }

        ItemIterable<CmisObject> cmisObjects = cmisFolder.getChildren();

        for (CmisObject cmisObject : cmisObjects) {
            if (cmisObject instanceof Document) {
                Document document = (Document) cmisObject;

                deleteMappedFileEntry(document);
            } else if (cmisObject instanceof org.apache.chemistry.opencmis.client.api.Folder) {

                org.apache.chemistry.opencmis.client.api.Folder cmisSubfolder = (org.apache.chemistry.opencmis.client.api.Folder) cmisObject;

                try {
                    repositoryEntryLocalService.deleteRepositoryEntry(getRepositoryId(), cmisObject.getId());

                    if (_cmisRepositoryConfiguration.deleteDepth() == _DELETE_DEEP) {

                        deleteMappedFolder(cmisSubfolder);
                    }
                } catch (NoSuchRepositoryEntryException nsree) {
                    if (_log.isWarnEnabled()) {
                        _log.warn(nsree, nsree);
                    }
                }
            }
        }
    }

    protected Hits doSearch(SearchContext searchContext, Query query) throws Exception {

        long startTime = System.currentTimeMillis();

        Session session = getSession();

        RepositoryInfo repositoryInfo = session.getRepositoryInfo();

        RepositoryCapabilities repositoryCapabilities = repositoryInfo.getCapabilities();

        QueryConfig queryConfig = searchContext.getQueryConfig();

        CapabilityQuery capabilityQuery = repositoryCapabilities.getQueryCapability();

        queryConfig.setAttribute("capabilityQuery", capabilityQuery.value());

        String productName = repositoryInfo.getProductName();
        String productVersion = repositoryInfo.getProductVersion();

        queryConfig.setAttribute("repositoryProductName", productName);
        queryConfig.setAttribute("repositoryProductVersion", productVersion);

        String queryString = _cmisSearchQueryBuilder.buildQuery(searchContext, query);

        if (_cmisRepositoryDetector.isNuxeo5_4()) {
            queryString += " AND (" + PropertyIds.IS_LATEST_VERSION + " = true)";
        }

        if (_log.isDebugEnabled()) {
            _log.debug("CMIS search query: " + queryString);
        }

        boolean searchAllVersions = _cmisRepositoryDetector.isNuxeo5_5OrHigher();

        ItemIterable<QueryResult> queryResults = session.query(queryString, searchAllVersions);

        int start = searchContext.getStart();
        int end = searchContext.getEnd();

        if ((start == QueryUtil.ALL_POS) && (end == QueryUtil.ALL_POS)) {
            start = 0;
        }

        int total = 0;

        List<com.liferay.portal.kernel.search.Document> documents = new ArrayList<>();
        List<String> snippets = new ArrayList<>();
        List<Float> scores = new ArrayList<>();

        for (QueryResult queryResult : queryResults) {
            total++;

            if (total <= start) {
                continue;
            }

            if ((total > end) && (end != QueryUtil.ALL_POS)) {
                continue;
            }

            com.liferay.portal.kernel.search.Document document = new DocumentImpl();

            String objectId = queryResult.getPropertyValueByQueryName(PropertyIds.OBJECT_ID);

            if (_log.isDebugEnabled()) {
                _log.debug("Search result object ID " + objectId);
            }

            FileEntry fileEntry = null;

            try {
                fileEntry = toFileEntry(objectId, true);
            } catch (Exception e) {
                if (_log.isDebugEnabled()) {
                    Throwable cause = e.getCause();

                    if (cause != null) {
                        cause = cause.getCause();
                    }

                    if (cause instanceof CmisObjectNotFoundException) {
                        _log.debug("Search result ignored for CMIS document which "
                                + "has a version with an invalid object ID " + cause.getMessage());
                    } else {
                        _log.debug("Search result ignored for invalid object ID", e);
                    }
                }

                total--;

                continue;
            }

            DocumentHelper documentHelper = new DocumentHelper(document);

            documentHelper.setEntryKey(fileEntry.getModelClassName(), fileEntry.getFileEntryId());

            document.addKeyword(Field.TITLE, fileEntry.getTitle());

            documents.add(document);

            if (queryConfig.isScoreEnabled()) {
                Object scoreObj = queryResult.getPropertyValueByQueryName("HITS");

                if (scoreObj != null) {
                    scores.add(Float.valueOf(scoreObj.toString()));
                } else {
                    scores.add(1.0F);
                }
            } else {
                scores.add(1.0F);
            }

            snippets.add(StringPool.BLANK);
        }

        float searchTime = (float) (System.currentTimeMillis() - startTime) / Time.SECOND;

        Hits hits = new HitsImpl();

        hits.setDocs(documents.toArray(new com.liferay.portal.kernel.search.Document[documents.size()]));
        hits.setLength(total);
        hits.setQuery(query);
        hits.setQueryTerms(new String[0]);
        hits.setScores(ArrayUtil.toFloatArray(scores));
        hits.setSearchTime(searchTime);
        hits.setSnippets(snippets.toArray(new String[snippets.size()]));
        hits.setStart(startTime);

        return hits;
    }

    protected org.apache.chemistry.opencmis.client.api.Folder getCmisFolder(Session session, long folderId)
            throws PortalException {

        Folder folder = getFolder(session, folderId);

        org.apache.chemistry.opencmis.client.api.Folder cmisFolder = (org.apache.chemistry.opencmis.client.api.Folder) folder
                .getModel();

        return cmisFolder;
    }

    protected List<String> getCmisFolderIds(Session session, long folderId) throws PortalException {

        StringBundler sb = new StringBundler(4);

        sb.append("SELECT cmis:objectId FROM cmis:folder");

        if (folderId > 0) {
            sb.append(" WHERE IN_FOLDER(");

            String objectId = toFolderId(session, folderId);

            sb.append(StringUtil.quote(objectId));

            sb.append(StringPool.CLOSE_PARENTHESIS);
        }

        String query = sb.toString();

        if (_log.isDebugEnabled()) {
            _log.debug("Calling query " + query);
        }

        ItemIterable<QueryResult> queryResults = session.query(query, isAllVersionsSearchableSupported(session));

        List<String> cmsFolderIds = new ArrayList<>();

        for (QueryResult queryResult : queryResults) {
            PropertyData<String> propertyData = queryResult.getPropertyById(PropertyIds.OBJECT_ID);

            List<String> values = propertyData.getValues();

            String value = values.get(0);

            cmsFolderIds.add(value);
        }

        return cmsFolderIds;
    }

    protected Document getDocument(Session session, long fileEntryId) throws PortalException {

        try {
            String versionSeriesId = toFileEntryId(fileEntryId);

            return (Document) session.getObject(versionSeriesId);
        } catch (CmisObjectNotFoundException confe) {
            throw new NoSuchFileEntryException("No CMIS file entry with {fileEntryId=" + fileEntryId + "}", confe);
        }
    }

    protected List<String> getDocumentIds(Session session, long folderId, String[] mimeTypes)
            throws PortalException {

        StringBundler sb = new StringBundler();

        sb.append("SELECT cmis:objectId FROM cmis:document");

        if (ArrayUtil.isNotEmpty(mimeTypes)) {
            sb.append(" WHERE cmis:contentStreamMimeType IN (");

            for (int i = 0; i < mimeTypes.length; i++) {
                sb.append(StringUtil.quote(mimeTypes[i]));

                if ((i + 1) < mimeTypes.length) {
                    sb.append(", ");
                }
            }

            sb.append(StringPool.CLOSE_PARENTHESIS);
        }

        if (folderId > 0) {
            if (ArrayUtil.isNotEmpty(mimeTypes)) {
                sb.append(" AND ");
            } else {
                sb.append(" WHERE ");
            }

            sb.append("IN_FOLDER(");

            String objectId = toFolderId(session, folderId);

            sb.append(StringUtil.quote(objectId));

            sb.append(StringPool.CLOSE_PARENTHESIS);
        }

        String query = sb.toString();

        if (_log.isDebugEnabled()) {
            _log.debug("Calling query " + query);
        }

        ItemIterable<QueryResult> queryResults = session.query(query, false);

        List<String> cmisDocumentIds = new ArrayList<>();

        for (QueryResult queryResult : queryResults) {
            String objectId = queryResult.getPropertyValueByQueryName(PropertyIds.OBJECT_ID);

            cmisDocumentIds.add(objectId);
        }

        return cmisDocumentIds;
    }

    protected List<FileEntry> getFileEntries(long folderId) {
        cacheFoldersAndFileEntries(folderId);

        return _cmisModelCache.getFileEntries(folderId);
    }

    protected List<FileEntry> getFileEntries(long folderId, long repositoryId) {
        return new ArrayList<>();
    }

    protected FileVersion getFileVersion(Session session, FileEntry fileEntry, long fileVersionId)
            throws PortalException {

        try {
            String objectId = toFileVersionId(fileVersionId);

            return toFileVersion(fileEntry, (Document) session.getObject(objectId));
        } catch (CmisObjectNotFoundException confe) {
            throw new NoSuchFileVersionException("No CMIS file version with {fileVersionId=" + fileVersionId + "}",
                    confe);
        }
    }

    protected Folder getFolder(Session session, long folderId) throws PortalException {

        try {
            Folder folder = _cmisModelCache.getFolder(folderId);

            if (folder == null) {
                String objectId = toFolderId(session, folderId);

                CmisObject cmisObject = session.getObject(objectId);

                folder = (Folder) toFolderOrFileEntry(cmisObject);

                _cmisModelCache.putFolder(folder);
            }

            return folder;
        } catch (CmisObjectNotFoundException confe) {
            throw new NoSuchFolderException("No CMIS folder with {folderId=" + folderId + "}", confe);
        }
    }

    protected List<Folder> getFolders(long parentFolderId) throws PortalException {

        List<Folder> folders = _cmisModelCache.getFolders(parentFolderId);

        if (folders == null) {
            List<String> folderIds = getCmisFolderIds(getSession(), parentFolderId);

            folders = new ArrayList<>(folderIds.size());

            for (String folderId : folderIds) {
                folders.add(toFolder(folderId));
            }

            _cmisModelCache.putFolders(parentFolderId, folders);
        }

        return folders;
    }

    protected List<Object> getFoldersAndFileEntries(long folderId) {
        cacheFoldersAndFileEntries(folderId);

        return _cmisModelCache.getFoldersAndFileEntries(folderId);
    }

    protected String getObjectId(Session session, long folderId, boolean fileEntry, String name)
            throws PortalException {

        String objectId = toFolderId(session, folderId);

        StringBundler sb = new StringBundler(7);

        sb.append("SELECT cmis:objectId FROM ");

        if (fileEntry) {
            sb.append("cmis:document ");
        } else {
            sb.append("cmis:folder ");
        }

        sb.append("WHERE cmis:name = '");
        sb.append(name);
        sb.append("' AND IN_FOLDER('");
        sb.append(objectId);
        sb.append("')");

        String query = sb.toString();

        if (_log.isDebugEnabled()) {
            _log.debug("Calling query " + query);
        }

        ItemIterable<QueryResult> queryResults = session.query(query, false);

        Iterator<QueryResult> itr = queryResults.iterator();

        if (itr.hasNext()) {
            QueryResult queryResult = itr.next();

            PropertyData<String> propertyData = queryResult.getPropertyById(PropertyIds.OBJECT_ID);

            List<String> values = propertyData.getValues();

            return values.get(0);
        }

        return null;
    }

    protected void getSubfolderIds(List<Long> subfolderIds, List<Folder> subfolders, boolean recurse)
            throws PortalException {

        for (Folder subfolder : subfolders) {
            long subfolderId = subfolder.getFolderId();

            subfolderIds.add(subfolderId);

            if (recurse) {
                List<Folder> subSubFolders = getFolders(subfolderId, false, QueryUtil.ALL_POS, QueryUtil.ALL_POS,
                        null);

                getSubfolderIds(subfolderIds, subSubFolders, recurse);
            }
        }
    }

    protected boolean isActionAllowable(String objectId, Action action) throws PortalException {

        Session session = getSession();

        Document document = (Document) session.getObject(objectId);

        AllowableActions allowableActions = document.getAllowableActions();

        Set<Action> allowableActionsSet = allowableActions.getAllowableActions();

        if (allowableActionsSet.contains(action)) {
            return true;
        } else {
            return false;
        }
    }

    protected boolean isAllVersionsSearchableSupported(Session session) {
        RepositoryInfo repositoryInfo = session.getRepositoryInfo();

        RepositoryCapabilities repositoryCapabilities = repositoryInfo.getCapabilities();

        return repositoryCapabilities.isAllVersionsSearchableSupported();
    }

    protected void processException(Exception e) throws PortalException {
        if ((e instanceof CmisRuntimeException && e.getMessage().contains("authorized"))
                || (e instanceof CmisPermissionDeniedException)) {

            String login = null;

            try {
                login = _cmisRepositoryHandler.getLogin();
            } catch (Exception e2) {
            }

            throw new PrincipalException.MustBeAuthenticated(login);
        }
    }

    protected <E> List<E> subList(List<E> list, int start, int end, OrderByComparator<E> obc) {

        if ((obc != null) && ((obc instanceof RepositoryModelCreateDateComparator)
                || (obc instanceof RepositoryModelModifiedDateComparator)
                || (obc instanceof RepositoryModelSizeComparator)
                || (obc instanceof RepositoryModelTitleComparator))) {

            list = ListUtil.sort(list, obc);
        }

        return ListUtil.subList(list, start, end);
    }

    protected FileEntry toFileEntry(Document document, boolean strict) throws PortalException {

        RepositoryEntry repositoryEntry = null;

        if (isDocumentRetrievableByVersionSeriesId()) {
            repositoryEntry = getRepositoryEntry(document.getVersionSeriesId());
        } else {
            repositoryEntry = getRepositoryEntry(document.getId());
        }

        return new CMISFileEntry(this, repositoryEntry.getUuid(), repositoryEntry.getRepositoryEntryId(), document,
                _lockManager);
    }

    protected FileEntry toFileEntry(String objectId, boolean strict) throws PortalException {

        try {
            Session session = getSession();

            Document document = (Document) session.getObject(objectId);

            return toFileEntry(document, strict);
        } catch (CmisObjectNotFoundException confe) {
            throw new NoSuchFileEntryException("No CMIS file entry with {objectId=" + objectId + "}", confe);
        } catch (SystemException se) {
            throw se;
        } catch (Exception e) {
            processException(e);

            throw new RepositoryException(e);
        }
    }

    protected String toFileEntryId(long fileEntryId) throws PortalException {
        RepositoryEntry repositoryEntry = repositoryEntryLocalService.fetchRepositoryEntry(fileEntryId);

        if (repositoryEntry == null) {
            throw new NoSuchFileEntryException("No CMIS file entry with {fileEntryId=" + fileEntryId + "}");
        }

        return repositoryEntry.getMappedId();
    }

    protected String toFileVersionId(long fileVersionId) throws PortalException {

        RepositoryEntry repositoryEntry = repositoryEntryLocalService.fetchRepositoryEntry(fileVersionId);

        if (repositoryEntry == null) {
            throw new NoSuchFileVersionException("No CMIS file version with {fileVersionId=" + fileVersionId + "}");
        }

        return repositoryEntry.getMappedId();
    }

    protected String toFolderId(Session session, long folderId) throws PortalException {

        RepositoryEntry repositoryEntry = repositoryEntryLocalService.fetchRepositoryEntry(folderId);

        if (repositoryEntry != null) {
            return repositoryEntry.getMappedId();
        }

        DLFolder dlFolder = dlFolderLocalService.fetchFolder(folderId);

        if (dlFolder == null) {
            throw new NoSuchFolderException("No CMIS folder with {folderId=" + folderId + "}");
        } else if (!dlFolder.isMountPoint()) {
            throw new RepositoryException("CMIS repository should not be used with {folderId=" + folderId + "}");
        }

        RepositoryInfo repositoryInfo = session.getRepositoryInfo();

        String rootFolderId = repositoryInfo.getRootFolderId();

        repositoryEntry = repositoryEntryLocalService.getRepositoryEntry(dlFolder.getUserId(), getGroupId(),
                getRepositoryId(), rootFolderId);

        return repositoryEntry.getMappedId();
    }

    protected Object toFolderOrFileEntry(CmisObject cmisObject) throws PortalException {

        if (cmisObject instanceof Document) {
            return toFileEntry((Document) cmisObject);
        } else if (cmisObject instanceof org.apache.chemistry.opencmis.client.api.Folder) {

            org.apache.chemistry.opencmis.client.api.Folder cmisFolder = (org.apache.chemistry.opencmis.client.api.Folder) cmisObject;

            return toFolder(cmisFolder);
        } else {
            return null;
        }
    }

    protected void updateMappedId(long repositoryEntryId, String mappedId) throws PortalException {

        RepositoryEntry repositoryEntry = repositoryEntryLocalService.getRepositoryEntry(repositoryEntryId);

        if (!mappedId.equals(repositoryEntry.getMappedId())) {
            RepositoryEntryLocalServiceUtil.updateRepositoryEntry(repositoryEntryId, mappedId);
        }
    }

    protected void validateTitle(Session session, long folderId, String title) throws PortalException {

        String objectId = getObjectId(session, folderId, true, title);

        if (objectId != null) {
            throw new DuplicateFileEntryException(title);
        }

        objectId = getObjectId(session, folderId, false, title);

        if (objectId != null) {
            throw new DuplicateFolderNameException(title);
        }
    }

    private static final int _DELETE_DEEP = -1;

    private static final int _DELETE_NONE = 0;

    private static final Log _log = LogFactoryUtil.getLog(CMISRepository.class);

    private static final CMISModelCache _cmisModelCache = new CMISModelCache();

    private final CMISRepositoryConfiguration _cmisRepositoryConfiguration;
    private CMISRepositoryDetector _cmisRepositoryDetector;
    private final CMISRepositoryHandler _cmisRepositoryHandler;
    private final CMISSearchQueryBuilder _cmisSearchQueryBuilder;
    private final CMISSessionCache _cmisSessionCache;
    private final LockManager _lockManager;
    private String _sessionKey;

}