org.pentaho.platform.repository2.unified.jcr.JcrRepositoryFileDao.java Source code

Java tutorial

Introduction

Here is the source code for org.pentaho.platform.repository2.unified.jcr.JcrRepositoryFileDao.java

Source

/*
 * This program is free software; you can redistribute it and/or modify it under the
 * terms of the GNU General Public License, version 2 as published by the Free Software
 * Foundation.
 *
 * You should have received a copy of the GNU General Public License along with this
 * program; if not, you can obtain a copy at http://www.gnu.org/licenses/gpl-2.0.html
 * or from the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * This program 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 General Public License for more details.
 *
 *
 * Copyright 2006 - 2013 Pentaho Corporation.  All rights reserved.
 */

package org.pentaho.platform.repository2.unified.jcr;

import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import javax.jcr.AccessDeniedException;
import javax.jcr.Item;
import javax.jcr.ItemExistsException;
import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
import javax.jcr.PropertyIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.lock.Lock;

import org.pentaho.platform.api.locale.IPentahoLocale;
import org.pentaho.platform.api.repository2.unified.IRepositoryAccessVoterManager;
import org.pentaho.platform.api.repository2.unified.IRepositoryDefaultAclHandler;
import org.pentaho.platform.api.repository2.unified.IRepositoryFileData;
import org.pentaho.platform.api.repository2.unified.RepositoryFile;
import org.pentaho.platform.api.repository2.unified.RepositoryFileAcl;
import org.pentaho.platform.api.repository2.unified.RepositoryFilePermission;
import org.pentaho.platform.api.repository2.unified.RepositoryFileTree;
import org.pentaho.platform.api.repository2.unified.RepositoryRequest;
import org.pentaho.platform.api.repository2.unified.UnifiedRepositoryException;
import org.pentaho.platform.api.repository2.unified.VersionSummary;
import org.pentaho.platform.api.repository2.unified.data.node.DataNode;
import org.pentaho.platform.api.repository2.unified.data.node.NodeRepositoryFileData;
import org.pentaho.platform.engine.core.system.PentahoSessionHolder;
import org.pentaho.platform.engine.core.system.PentahoSystem;
import org.pentaho.platform.repository2.messages.Messages;
import org.pentaho.platform.repository2.unified.IRepositoryFileAclDao;
import org.pentaho.platform.repository2.unified.IRepositoryFileDao;
import org.pentaho.platform.repository2.unified.ServerRepositoryPaths;
import org.springframework.extensions.jcr.JcrCallback;
import org.springframework.extensions.jcr.JcrTemplate;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

/**
 * CRUD operations against JCR. Note that there is no access control in this class (implicit or explicit).
 * 
 * @author mlowery
 */
public class JcrRepositoryFileDao implements IRepositoryFileDao {

    // ~ Static fields/initializers
    // ======================================================================================

    // ~ Instance fields
    // =================================================================================================
    private JcrTemplate jcrTemplate;

    private List<ITransformer<IRepositoryFileData>> transformers;

    private ILockHelper lockHelper;

    private IDeleteHelper deleteHelper;

    private IPathConversionHelper pathConversionHelper;

    private IRepositoryFileAclDao aclDao;

    private IRepositoryDefaultAclHandler defaultAclHandler;

    private IRepositoryAccessVoterManager accessVoterManager;

    // ~ Constructors
    // ====================================================================================================

    public JcrRepositoryFileDao(final JcrTemplate jcrTemplate,
            final List<ITransformer<IRepositoryFileData>> transformers, final ILockHelper lockHelper,
            final IDeleteHelper deleteHelper, final IPathConversionHelper pathConversionHelper,
            final IRepositoryFileAclDao aclDao, final IRepositoryDefaultAclHandler defaultAclHandler) {
        super();
        Assert.notNull(jcrTemplate);
        Assert.notNull(transformers);
        this.jcrTemplate = jcrTemplate;
        this.transformers = transformers;
        this.lockHelper = lockHelper;
        this.deleteHelper = deleteHelper;
        this.pathConversionHelper = pathConversionHelper;
        this.aclDao = aclDao;
        this.defaultAclHandler = defaultAclHandler;
    }

    public JcrRepositoryFileDao(final JcrTemplate jcrTemplate,
            final List<ITransformer<IRepositoryFileData>> transformers, final ILockHelper lockHelper,
            final IDeleteHelper deleteHelper, final IPathConversionHelper pathConversionHelper,
            final IRepositoryFileAclDao aclDao, final IRepositoryDefaultAclHandler defaultAclHandler,
            final IRepositoryAccessVoterManager accessVoterManager) {
        this(jcrTemplate, transformers, lockHelper, deleteHelper, pathConversionHelper, aclDao, defaultAclHandler);
        this.accessVoterManager = accessVoterManager;
    }

    // ~ Methods
    // =========================================================================================================

    private RepositoryFile internalCreateFolder(final Session session, final Serializable parentFolderId,
            final RepositoryFile folder, final RepositoryFileAcl acl, final String versionMessage)
            throws RepositoryException {
        if (isKioskEnabled()) {
            throw new RuntimeException(
                    Messages.getInstance().getString("JcrRepositoryFileDao.ERROR_0006_ACCESS_DENIED")); //$NON-NLS-1$
        }

        // Get repository file info and acl info of parent
        if (parentFolderId != null) {
            RepositoryFile parentRepositoryFile = getFileById(parentFolderId);
            if (parentRepositoryFile != null) {
                RepositoryFileAcl parentAcl = aclDao.getAcl(parentRepositoryFile.getId());
                // Invoke accessVoterManager to see if we have access to perform this operation
                if (!accessVoterManager.hasAccess(parentRepositoryFile, RepositoryFilePermission.WRITE, parentAcl,
                        PentahoSessionHolder.getSession())) {
                    return null;
                }
            }
        }
        PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);
        JcrRepositoryFileUtils.checkoutNearestVersionableFileIfNecessary(session, pentahoJcrConstants,
                parentFolderId);
        Node folderNode = JcrRepositoryFileUtils.createFolderNode(session, pentahoJcrConstants, parentFolderId,
                folder);
        // create a temporary folder object with correct path for default acl purposes.
        String path = JcrRepositoryFileUtils.getAbsolutePath(session, pentahoJcrConstants, folderNode);
        RepositoryFile tmpFolder = new RepositoryFile.Builder(folder).path(path).build();
        // we must create the acl during checkout
        JcrRepositoryFileAclUtils.createAcl(session, pentahoJcrConstants, folderNode.getIdentifier(),
                acl == null ? defaultAclHandler.createDefaultAcl(tmpFolder) : acl);
        session.save();
        if (folder.isVersioned()) {
            JcrRepositoryFileUtils.checkinNearestVersionableNodeIfNecessary(session, pentahoJcrConstants,
                    folderNode, versionMessage);
        }
        JcrRepositoryFileUtils.checkinNearestVersionableFileIfNecessary(session, pentahoJcrConstants,
                parentFolderId,
                Messages.getInstance().getString("JcrRepositoryFileDao.USER_0001_VER_COMMENT_ADD_FOLDER", //$NON-NLS-1$
                        folder.getName(), (parentFolderId == null ? "root" : parentFolderId.toString()))); //$NON-NLS-1$
        return JcrRepositoryFileUtils.nodeToFile(session, pentahoJcrConstants, pathConversionHelper, lockHelper,
                folderNode);
    }

    private RepositoryFile internalCreateFile(final Serializable parentFolderId, final RepositoryFile file,
            final IRepositoryFileData content, final RepositoryFileAcl acl, final String versionMessage) {
        if (isKioskEnabled()) {
            throw new RuntimeException(
                    Messages.getInstance().getString("JcrRepositoryFileDao.ERROR_0006_ACCESS_DENIED")); //$NON-NLS-1$
        }

        /*
         * PPP-3049: Changed the Assert.notNull(content) to code that creates a file with a single blank when the assert
         * WOULD have been triggered.
         */
        Assert.notNull(file);
        Assert.isTrue(!file.isFolder());

        // Get repository file info and acl info of parent
        if (parentFolderId != null) {
            RepositoryFile parentRepositoryFile = getFileById(parentFolderId);
            if (parentRepositoryFile != null) {
                RepositoryFileAcl parentAcl = aclDao.getAcl(parentRepositoryFile.getId());
                // Invoke accessVoterManager to see if we have access to perform this operation
                if (!accessVoterManager.hasAccess(parentRepositoryFile, RepositoryFilePermission.WRITE, parentAcl,
                        PentahoSessionHolder.getSession())) {
                    return null;
                }
            }
        }
        // Assert.notNull(content);
        DataNode emptyDataNode = new DataNode(file.getName());
        emptyDataNode.setProperty(" ", "content"); //$NON-NLS-1$ //$NON-NLS-2$
        final IRepositoryFileData emptyContent = new NodeRepositoryFileData(emptyDataNode);

        return (RepositoryFile) jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);
                JcrRepositoryFileUtils.checkoutNearestVersionableFileIfNecessary(session, pentahoJcrConstants,
                        parentFolderId);
                Node fileNode = JcrRepositoryFileUtils.createFileNode(session, pentahoJcrConstants, parentFolderId,
                        file, content == null ? emptyContent : content,
                        findTransformerForWrite(content == null ? emptyContent.getClass() : content.getClass()));
                // create a tmp file with correct path for default acl creation purposes.
                String path = JcrRepositoryFileUtils.getAbsolutePath(session, pentahoJcrConstants, fileNode);
                RepositoryFile tmpFile = new RepositoryFile.Builder(file).path(path).build();
                // we must create the acl during checkout
                aclDao.createAcl(fileNode.getIdentifier(),
                        acl == null ? defaultAclHandler.createDefaultAcl(tmpFile) : acl);
                session.save();
                if (file.isVersioned()) {
                    JcrRepositoryFileUtils.checkinNearestVersionableNodeIfNecessary(session, pentahoJcrConstants,
                            fileNode, versionMessage, file.getCreatedDate(), false);

                }
                JcrRepositoryFileUtils.checkinNearestVersionableFileIfNecessary(session, pentahoJcrConstants,
                        parentFolderId,
                        Messages.getInstance().getString("JcrRepositoryFileDao.USER_0002_VER_COMMENT_ADD_FILE", //$NON-NLS-1$
                                file.getName(), (parentFolderId == null ? "root" : parentFolderId.toString()))); //$NON-NLS-1$
                return JcrRepositoryFileUtils.nodeToFile(session, pentahoJcrConstants, pathConversionHelper,
                        lockHelper, fileNode);
            }
        });
    }

    private RepositoryFile internalUpdateFile(final Session session, final PentahoJcrConstants pentahoJcrConstants,
            final RepositoryFile file, final IRepositoryFileData content, final String versionMessage)
            throws RepositoryException {
        if (isKioskEnabled()) {
            throw new RuntimeException(
                    Messages.getInstance().getString("JcrRepositoryFileDao.ERROR_0006_ACCESS_DENIED")); //$NON-NLS-1$
        }

        Assert.notNull(file);
        Assert.isTrue(!file.isFolder());
        Assert.notNull(content);
        // Get repository file info and acl info of parent
        RepositoryFileAcl acl = aclDao.getAcl(file.getId());
        // Invoke accessVoterManager to see if we have access to perform this operation
        if (!accessVoterManager.hasAccess(file, RepositoryFilePermission.WRITE, acl,
                PentahoSessionHolder.getSession())) {
            return null;
        }
        lockHelper.addLockTokenToSessionIfNecessary(session, pentahoJcrConstants, file.getId());
        JcrRepositoryFileUtils.checkoutNearestVersionableFileIfNecessary(session, pentahoJcrConstants,
                file.getId());
        JcrRepositoryFileUtils.updateFileNode(session, pentahoJcrConstants, file, content,
                findTransformerForWrite(content.getClass()));
        session.save();
        JcrRepositoryFileUtils.checkinNearestVersionableFileIfNecessary(session, pentahoJcrConstants, file.getId(),
                versionMessage, file.getCreatedDate() != null ? file.getCreatedDate() : new java.util.Date(), true);
        lockHelper.removeLockTokenFromSessionIfNecessary(session, pentahoJcrConstants, file.getId());
        return JcrRepositoryFileUtils.nodeIdToFile(session, pentahoJcrConstants, pathConversionHelper, lockHelper,
                file.getId());
    }

    private RepositoryFile internalUpdateFolder(final Session session,
            final PentahoJcrConstants pentahoJcrConstants, final RepositoryFile folder, final String versionMessage)
            throws RepositoryException {
        if (isKioskEnabled()) {
            throw new RuntimeException(
                    Messages.getInstance().getString("JcrRepositoryFileDao.ERROR_0006_ACCESS_DENIED")); //$NON-NLS-1$
        }

        Assert.notNull(folder);
        Assert.isTrue(folder.isFolder());
        lockHelper.addLockTokenToSessionIfNecessary(session, pentahoJcrConstants, folder.getId());
        JcrRepositoryFileUtils.checkoutNearestVersionableFileIfNecessary(session, pentahoJcrConstants,
                folder.getId());
        JcrRepositoryFileUtils.updateFolderNode(session, pentahoJcrConstants, folder);
        session.save();
        JcrRepositoryFileUtils.checkinNearestVersionableFileIfNecessary(session, pentahoJcrConstants,
                folder.getId(), versionMessage);
        lockHelper.removeLockTokenFromSessionIfNecessary(session, pentahoJcrConstants, folder.getId());
        return JcrRepositoryFileUtils.nodeIdToFile(session, pentahoJcrConstants, pathConversionHelper, lockHelper,
                folder.getId());
    }

    protected ITransformer<IRepositoryFileData> findTransformerForRead(final String contentType,
            final Class<? extends IRepositoryFileData> clazz) {
        for (ITransformer<IRepositoryFileData> transformer : transformers) {
            if (transformer.canRead(contentType, clazz)) {
                return transformer;
            }
        }
        throw new IllegalArgumentException(
                Messages.getInstance().getString("JcrRepositoryFileDao.ERROR_0001_NO_TRANSFORMER")); //$NON-NLS-1$
    }

    protected ITransformer<IRepositoryFileData> findTransformerForWrite(
            final Class<? extends IRepositoryFileData> clazz) {
        for (ITransformer<IRepositoryFileData> transformer : transformers) {
            if (transformer.canWrite(clazz)) {
                return transformer;
            }
        }
        throw new IllegalArgumentException(
                Messages.getInstance().getString("JcrRepositoryFileDao.ERROR_0001_NO_TRANSFORMER")); //$NON-NLS-1$
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public RepositoryFile createFile(final Serializable parentFolderId, final RepositoryFile file,
            final IRepositoryFileData content, final RepositoryFileAcl acl, final String versionMessage) {
        return internalCreateFile(parentFolderId, file, content, acl, versionMessage);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public RepositoryFile createFolder(final Serializable parentFolderId, final RepositoryFile folder,
            final RepositoryFileAcl acl, final String versionMessage) {
        Assert.notNull(folder);
        Assert.isTrue(folder.isFolder());

        return (RepositoryFile) jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                return internalCreateFolder(session, parentFolderId, folder, acl, versionMessage);
            }
        });
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public RepositoryFile getFileById(final Serializable fileId) {
        return internalGetFileById(fileId, false, null);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public RepositoryFile getFileById(final Serializable fileId, final boolean loadMaps) {
        return internalGetFileById(fileId, loadMaps, null);
    }

    @Override
    public RepositoryFile getFile(final String relPath, final IPentahoLocale locale) {
        return getFile(relPath, false, locale);
    }

    @Override
    public RepositoryFile getFileById(Serializable fileId, IPentahoLocale locale) {
        return internalGetFileById(fileId, false, locale);
    }

    @Override
    public RepositoryFile getFile(final String relPath, final boolean loadLocaleMaps, final IPentahoLocale locale) {
        Assert.hasText(relPath);
        Assert.isTrue(relPath.startsWith(RepositoryFile.SEPARATOR));

        return (RepositoryFile) jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                String absPath = pathConversionHelper.relToAbs(relPath);
                return internalGetFile(session, absPath, loadLocaleMaps, locale);
            }
        });
    }

    @Override
    public RepositoryFile getFileById(Serializable fileId, boolean loadLocaleMaps, IPentahoLocale locale) {
        return internalGetFileById(fileId, loadLocaleMaps, locale);
    }

    private RepositoryFile internalGetFileById(final Serializable fileId, final boolean loadMaps,
            final IPentahoLocale locale) {
        Assert.notNull(fileId);
        return (RepositoryFile) jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);
                Node fileNode = session.getNodeByIdentifier(fileId.toString());
                RepositoryFile file = fileNode != null
                        ? JcrRepositoryFileUtils.nodeToFile(session, pentahoJcrConstants, pathConversionHelper,
                                lockHelper, fileNode, loadMaps, locale)
                        : null;
                if (file != null) {
                    RepositoryFileAcl acl = aclDao.getAcl(file.getId());
                    // Invoke accessVoterManager to see if we have access to perform this operation
                    if (!accessVoterManager.hasAccess(file, RepositoryFilePermission.READ, acl,
                            PentahoSessionHolder.getSession())) {
                        return null;
                    }
                }
                return file;
            }
        });
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public RepositoryFile getFile(final String relPath) {
        return getFile(relPath, false, null);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public RepositoryFile getFileByAbsolutePath(final String absPath) {
        Assert.hasText(absPath);
        Assert.isTrue(absPath.startsWith(RepositoryFile.SEPARATOR));
        return (RepositoryFile) jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                return internalGetFile(session, absPath, false, null);
            }
        });
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public RepositoryFile getFile(final String relPath, final boolean loadMaps) {
        Assert.hasText(relPath);
        Assert.isTrue(relPath.startsWith(RepositoryFile.SEPARATOR));
        return (RepositoryFile) jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                String absPath = pathConversionHelper.relToAbs(relPath);
                return internalGetFile(session, absPath, loadMaps, null);
            }
        });
    }

    private RepositoryFile internalGetFile(final Session session, final String absPath, final boolean loadMaps,
            final IPentahoLocale locale) throws RepositoryException {

        PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);
        Item fileNode;
        try {
            fileNode = session.getItem(JcrStringHelper.pathEncode(absPath));
            // items are nodes or properties; this must be a node
            Assert.isTrue(fileNode.isNode());
        } catch (PathNotFoundException e) {
            fileNode = null;
        }
        RepositoryFile file = fileNode != null
                ? JcrRepositoryFileUtils.nodeToFile(session, pentahoJcrConstants, pathConversionHelper, lockHelper,
                        (Node) fileNode, loadMaps, locale)
                : null;
        if (file != null) {
            RepositoryFileAcl acl = aclDao.getAcl(file.getId());
            // Invoke accessVoterManager to see if we have access to perform this operation
            if (!accessVoterManager.hasAccess(file, RepositoryFilePermission.READ, acl,
                    PentahoSessionHolder.getSession())) {
                return null;
            }
        }
        return file;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @SuppressWarnings("unchecked")
    public <T extends IRepositoryFileData> T getData(final Serializable fileId, final Serializable versionId,
            final Class<T> contentClass) {
        Assert.notNull(fileId);
        return (T) jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);
                IRepositoryFileData data = JcrRepositoryFileUtils.getContent(session, pentahoJcrConstants, fileId,
                        versionId, findTransformerForRead(JcrRepositoryFileUtils.getFileContentType(session,
                                pentahoJcrConstants, fileId, versionId), contentClass));
                if (fileId != null) {
                    RepositoryFile file = internalGetFileById(fileId, false, null);
                    if (file != null) {
                        RepositoryFileAcl acl = aclDao.getAcl(fileId);
                        // Invoke accessVoterManager to see if we have access to perform this operation
                        if (!accessVoterManager.hasAccess(file, RepositoryFilePermission.READ, acl,
                                PentahoSessionHolder.getSession())) {
                            return null;
                        }
                    }
                }
                return data;
            }
        });

    }

    /**
     * {@inheritDoc}
     */
    @Override
    @SuppressWarnings("unchecked")
    public List<RepositoryFile> getChildren(final RepositoryRequest repositoryRequest) {
        Assert.notNull(repositoryRequest.getPath());
        return (List<RepositoryFile>) jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);
                return JcrRepositoryFileUtils.getChildren(session, pentahoJcrConstants, pathConversionHelper,
                        lockHelper, repositoryRequest);
            }
        });
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @SuppressWarnings("unchecked")
    public List<RepositoryFile> getChildren(final Serializable folderId, final String filter,
            final Boolean showHiddenFiles) {
        Assert.notNull(folderId);
        return (List<RepositoryFile>) jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);
                return JcrRepositoryFileUtils.getChildren(session, pentahoJcrConstants, pathConversionHelper,
                        lockHelper, folderId, filter, showHiddenFiles);
            }
        });
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public RepositoryFile updateFile(final RepositoryFile file, final IRepositoryFileData content,
            final String versionMessage) {
        if (isKioskEnabled()) {
            throw new RuntimeException(
                    Messages.getInstance().getString("JcrRepositoryFileDao.ERROR_0006_ACCESS_DENIED")); //$NON-NLS-1$
        }

        Assert.notNull(file);
        Assert.isTrue(!file.isFolder());
        return (RepositoryFile) jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);
                return internalUpdateFile(session, pentahoJcrConstants, file, content, versionMessage);
            }
        });
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void lockFile(final Serializable fileId, final String message) {
        if (isKioskEnabled()) {
            throw new RuntimeException(
                    Messages.getInstance().getString("JcrRepositoryFileDao.ERROR_0006_ACCESS_DENIED")); //$NON-NLS-1$
        }

        Assert.notNull(fileId);
        jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);
                lockHelper.lockFile(session, pentahoJcrConstants, fileId, message);
                return null;
            }
        });
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void unlockFile(final Serializable fileId) {
        if (isKioskEnabled()) {
            throw new RuntimeException(
                    Messages.getInstance().getString("JcrRepositoryFileDao.ERROR_0006_ACCESS_DENIED")); //$NON-NLS-1$
        }

        Assert.notNull(fileId);
        jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);
                lockHelper.unlockFile(session, pentahoJcrConstants, fileId);
                return null;
            }
        });
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @SuppressWarnings("unchecked")
    public List<VersionSummary> getVersionSummaries(final Serializable fileId) {
        Assert.notNull(fileId);
        return (List<VersionSummary>) jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);
                return JcrRepositoryFileUtils.getVersionSummaries(session, pentahoJcrConstants, fileId, true);
            }
        });
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public RepositoryFile getFile(final Serializable fileId, final Serializable versionId) {
        Assert.notNull(fileId);
        Assert.notNull(versionId);
        return (RepositoryFile) jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);
                return JcrRepositoryFileUtils.getFileAtVersion(session, pentahoJcrConstants, pathConversionHelper,
                        lockHelper, fileId, versionId);
            }
        });
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void deleteFile(final Serializable fileId, final String versionMessage) {
        if (isKioskEnabled()) {
            throw new RuntimeException(
                    Messages.getInstance().getString("JcrRepositoryFileDao.ERROR_0006_ACCESS_DENIED")); //$NON-NLS-1$
        }

        Assert.notNull(fileId);
        jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                RepositoryFile fileToBeDeleted = getFileById(fileId);
                // Get repository file info and acl info of parent
                if (fileToBeDeleted != null) {
                    RepositoryFileAcl toBeDeletedFileAcl = aclDao.getAcl(fileToBeDeleted.getId());
                    // Invoke accessVoterManager to see if we have access to perform this operation
                    if (!accessVoterManager.hasAccess(fileToBeDeleted, RepositoryFilePermission.DELETE,
                            toBeDeletedFileAcl, PentahoSessionHolder.getSession())) {
                        return null;
                    }
                }
                List<RepositoryFilePermission> perms = new ArrayList<RepositoryFilePermission>();
                perms.add(RepositoryFilePermission.DELETE);
                if (!aclDao.hasAccess(fileToBeDeleted.getPath(), EnumSet.copyOf(perms))) {
                    throw new AccessDeniedException(Messages.getInstance()
                            .getString("JcrRepositoryFileDao.ERROR_0006_ACCESS_DENIED_DELETE", fileId));
                }
                PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);
                Serializable parentFolderId = JcrRepositoryFileUtils.getParentId(session, fileId);
                JcrRepositoryFileUtils.checkoutNearestVersionableFileIfNecessary(session, pentahoJcrConstants,
                        parentFolderId);
                deleteHelper.deleteFile(session, pentahoJcrConstants, fileId);
                session.save();
                JcrRepositoryFileUtils.checkinNearestVersionableFileIfNecessary(session, pentahoJcrConstants,
                        parentFolderId, versionMessage);
                return null;
            }
        });
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void deleteFileAtVersion(final Serializable fileId, final Serializable versionId) {
        if (isKioskEnabled()) {
            throw new RuntimeException(
                    Messages.getInstance().getString("JcrRepositoryFileDao.ERROR_0006_ACCESS_DENIED")); //$NON-NLS-1$
        }

        Assert.notNull(fileId);
        Assert.notNull(versionId);
        jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                RepositoryFile fileToBeDeleted = getFileById(fileId);
                // Get repository file info and acl info of parent
                if (fileToBeDeleted != null) {
                    RepositoryFileAcl toBeDeletedFileAcl = aclDao.getAcl(fileToBeDeleted.getId());
                    // Invoke accessVoterManager to see if we have access to perform this operation
                    if (!accessVoterManager.hasAccess(fileToBeDeleted, RepositoryFilePermission.DELETE,
                            toBeDeletedFileAcl, PentahoSessionHolder.getSession())) {
                        return null;
                    }
                }
                Node fileToDeleteNode = session.getNodeByIdentifier(fileId.toString());
                session.getWorkspace().getVersionManager().getVersionHistory(fileToDeleteNode.getPath())
                        .removeVersion(versionId.toString());
                session.save();
                return null;
            }
        });
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @SuppressWarnings("unchecked")
    public List<RepositoryFile> getDeletedFiles(final String origParentFolderPath, final String filter) {
        Assert.hasLength(origParentFolderPath);
        return (List<RepositoryFile>) jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);
                return deleteHelper.getDeletedFiles(session, pentahoJcrConstants, origParentFolderPath, filter);
            }
        });
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @SuppressWarnings("unchecked")
    public List<RepositoryFile> getDeletedFiles() {
        return (List<RepositoryFile>) jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);
                return deleteHelper.getDeletedFiles(session, pentahoJcrConstants);
            }
        });
    }

    /**
     * {@inheritDoc}
     * <p/>
     * <p>
     * No checkout needed as .trash is not versioned.
     * </p>
     */
    @Override
    public void permanentlyDeleteFile(final Serializable fileId, final String versionMessage) {
        if (isKioskEnabled()) {
            throw new RuntimeException(
                    Messages.getInstance().getString("JcrRepositoryFileDao.ERROR_0006_ACCESS_DENIED")); //$NON-NLS-1$
        }

        Assert.notNull(fileId);
        jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                RepositoryFile fileToBeDeleted = getFileById(fileId);
                // Get repository file info and acl info of parent
                if (fileToBeDeleted != null) {
                    RepositoryFileAcl toBeDeletedFileAcl = aclDao.getAcl(fileToBeDeleted.getId());
                    // Invoke accessVoterManager to see if we have access to perform this operation
                    if (!accessVoterManager.hasAccess(fileToBeDeleted, RepositoryFilePermission.DELETE,
                            toBeDeletedFileAcl, PentahoSessionHolder.getSession())) {
                        return null;
                    }
                }
                PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);
                deleteHelper.permanentlyDeleteFile(session, pentahoJcrConstants, fileId);
                session.save();
                return null;
            }
        });
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void undeleteFile(final Serializable fileId, final String versionMessage) {
        if (isKioskEnabled()) {
            throw new RuntimeException(
                    Messages.getInstance().getString("JcrRepositoryFileDao.ERROR_0006_ACCESS_DENIED")); //$NON-NLS-1$
        }

        Assert.notNull(fileId);
        jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);
                String absOrigParentFolderPath = deleteHelper.getOriginalParentFolderPath(session,
                        pentahoJcrConstants, fileId);
                Serializable origParentFolderId = null;
                RepositoryFile file = getFileById(fileId);
                RepositoryFileAcl acl = aclDao.getAcl(fileId);
                if (!accessVoterManager.hasAccess(file, RepositoryFilePermission.WRITE, acl,
                        PentahoSessionHolder.getSession())) {
                    return null;
                }
                // original parent folder path may no longer exist!
                if (session.itemExists(JcrStringHelper.pathEncode(absOrigParentFolderPath))) {
                    origParentFolderId = ((Node) session
                            .getItem(JcrStringHelper.pathEncode(absOrigParentFolderPath))).getIdentifier();
                } else {
                    // go through each of the segments of the original parent folder path, creating as necessary
                    String[] segments = pathConversionHelper.absToRel(absOrigParentFolderPath)
                            .split(RepositoryFile.SEPARATOR);
                    RepositoryFile lastParentFolder = internalGetFile(session,
                            ServerRepositoryPaths.getTenantRootFolderPath(), false, null);
                    for (String segment : segments) {
                        if (StringUtils.hasLength(segment)) {
                            RepositoryFile tmp = internalGetFile(session, pathConversionHelper
                                    .relToAbs((lastParentFolder.getPath().equals(RepositoryFile.SEPARATOR) ? "" //$NON-NLS-1$
                                            : lastParentFolder.getPath()) + RepositoryFile.SEPARATOR + segment),
                                    false, null);
                            if (tmp == null) {
                                lastParentFolder = internalCreateFolder(session, lastParentFolder.getId(),
                                        new RepositoryFile.Builder(segment).folder(true).build(),
                                        defaultAclHandler.createDefaultAcl(lastParentFolder), null);
                            } else {
                                lastParentFolder = tmp;
                            }
                        }
                    }
                    origParentFolderId = lastParentFolder.getId();
                }
                JcrRepositoryFileUtils.checkoutNearestVersionableFileIfNecessary(session, pentahoJcrConstants,
                        origParentFolderId);
                deleteHelper.undeleteFile(session, pentahoJcrConstants, fileId);
                session.save();
                JcrRepositoryFileUtils.checkinNearestVersionableFileIfNecessary(session, pentahoJcrConstants,
                        origParentFolderId, versionMessage);
                return null;
            }
        });
    }

    private void internalCopyOrMove(final Serializable fileId, final String destRelPath,
            final String versionMessage, final boolean copy) {
        if (isKioskEnabled()) {
            throw new RuntimeException(
                    Messages.getInstance().getString("JcrRepositoryFileDao.ERROR_0006_ACCESS_DENIED")); //$NON-NLS-1$
        }

        Assert.notNull(fileId);
        jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                RepositoryFile file = getFileById(fileId);
                RepositoryFileAcl acl = aclDao.getAcl(fileId);
                if (!accessVoterManager.hasAccess(file, RepositoryFilePermission.WRITE, acl,
                        PentahoSessionHolder.getSession())) {
                    return null;
                }

                PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);
                String destAbsPath = pathConversionHelper.relToAbs(destRelPath);
                String cleanDestAbsPath = destAbsPath;
                if (cleanDestAbsPath.endsWith(RepositoryFile.SEPARATOR)) {
                    cleanDestAbsPath.substring(0, cleanDestAbsPath.length() - 1);
                }
                Node srcFileNode = session.getNodeByIdentifier(fileId.toString());
                Serializable srcParentFolderId = JcrRepositoryFileUtils.getParentId(session, fileId);
                boolean appendFileName = false;
                boolean destExists = true;
                Node destFileNode = null;
                Node destParentFolderNode = null;
                try {
                    destFileNode = (Node) session.getItem(JcrStringHelper.pathEncode(cleanDestAbsPath));
                } catch (PathNotFoundException e) {
                    destExists = false;
                }
                if (destExists) {
                    // make sure it's a file or folder
                    Assert.isTrue(JcrRepositoryFileUtils.isSupportedNodeType(pentahoJcrConstants, destFileNode));
                    // existing item; make sure src is not a folder if dest is a file
                    Assert.isTrue(
                            !(JcrRepositoryFileUtils.isPentahoFolder(pentahoJcrConstants, srcFileNode)
                                    && JcrRepositoryFileUtils.isPentahoFile(pentahoJcrConstants, destFileNode)),
                            Messages.getInstance().getString(
                                    "JcrRepositoryFileDao.ERROR_0002_CANNOT_OVERWRITE_FILE_WITH_FOLDER")); //$NON-NLS-1$
                    if (JcrRepositoryFileUtils.isPentahoFolder(pentahoJcrConstants, destFileNode)) {
                        // existing item; caller is not renaming file, only moving it
                        appendFileName = true;
                        destParentFolderNode = destFileNode;
                    } else {
                        // get parent of existing dest item
                        int lastSlashIndex = cleanDestAbsPath.lastIndexOf(RepositoryFile.SEPARATOR);
                        Assert.isTrue(lastSlashIndex > 1, Messages.getInstance()
                                .getString("JcrRepositoryFileDao.ERROR_0003_ILLEGAL_DEST_PATH")); //$NON-NLS-1$
                        String absPathToDestParentFolder = cleanDestAbsPath.substring(0, lastSlashIndex);
                        destParentFolderNode = (Node) session
                                .getItem(JcrStringHelper.pathEncode(absPathToDestParentFolder));
                    }
                } else {
                    // destination doesn't exist; go up one level to a folder that does exist
                    int lastSlashIndex = cleanDestAbsPath.lastIndexOf(RepositoryFile.SEPARATOR);
                    Assert.isTrue(lastSlashIndex > 1,
                            Messages.getInstance().getString("JcrRepositoryFileDao.ERROR_0003_ILLEGAL_DEST_PATH")); //$NON-NLS-1$
                    String absPathToDestParentFolder = cleanDestAbsPath.substring(0, lastSlashIndex);
                    // Not need to check the name if we encoded it
                    // JcrRepositoryFileUtils.checkName( cleanDestAbsPath.substring( lastSlashIndex + 1 ) );
                    try {
                        destParentFolderNode = (Node) session
                                .getItem(JcrStringHelper.pathEncode(absPathToDestParentFolder));
                    } catch (PathNotFoundException e1) {
                        Assert.isTrue(false, Messages.getInstance()
                                .getString("JcrRepositoryFileDao.ERROR_0004_PARENT_MUST_EXIST")); //$NON-NLS-1$
                    }
                    Assert.isTrue(JcrRepositoryFileUtils.isPentahoFolder(pentahoJcrConstants, destParentFolderNode),
                            Messages.getInstance()
                                    .getString("JcrRepositoryFileDao.ERROR_0005_PARENT_MUST_BE_FOLDER")); //$NON-NLS-1$
                }
                if (!copy) {
                    JcrRepositoryFileUtils.checkoutNearestVersionableFileIfNecessary(session, pentahoJcrConstants,
                            srcParentFolderId);
                }
                JcrRepositoryFileUtils.checkoutNearestVersionableNodeIfNecessary(session, pentahoJcrConstants,
                        destParentFolderNode);
                String finalEncodedSrcAbsPath = srcFileNode.getPath();
                String finalDestAbsPath = appendFileName && !file.isFolder()
                        ? cleanDestAbsPath + RepositoryFile.SEPARATOR + srcFileNode.getName()
                        : cleanDestAbsPath;
                try {
                    if (copy) {
                        session.getWorkspace().copy(finalEncodedSrcAbsPath,
                                JcrStringHelper.pathEncode(finalDestAbsPath));
                    } else {
                        session.getWorkspace().move(finalEncodedSrcAbsPath,
                                JcrStringHelper.pathEncode(finalDestAbsPath));
                    }
                } catch (ItemExistsException iae) {
                    throw new UnifiedRepositoryException((file.isFolder() ? "Folder " : "File ") + "with path ["
                            + cleanDestAbsPath + "] already exists in the repository");
                }

                JcrRepositoryFileUtils.checkinNearestVersionableNodeIfNecessary(session, pentahoJcrConstants,
                        destParentFolderNode, versionMessage);
                // if it's a move within the same folder, then the next checkin is unnecessary
                if (!copy && !destParentFolderNode.getIdentifier().equals(srcParentFolderId.toString())) {
                    JcrRepositoryFileUtils.checkinNearestVersionableFileIfNecessary(session, pentahoJcrConstants,
                            srcParentFolderId, versionMessage);
                }
                session.save();
                return null;
            }
        });
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void moveFile(final Serializable fileId, final String destRelPath, final String versionMessage) {
        internalCopyOrMove(fileId, destRelPath, versionMessage, false);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void copyFile(final Serializable fileId, final String destRelPath, final String versionMessage) {
        internalCopyOrMove(fileId, destRelPath, versionMessage, true);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public VersionSummary getVersionSummary(final Serializable fileId, final Serializable versionId) {
        Assert.notNull(fileId);
        return (VersionSummary) jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);
                return JcrRepositoryFileUtils.getVersionSummary(session, pentahoJcrConstants, fileId, versionId);
            }
        });
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void restoreFileAtVersion(final Serializable fileId, final Serializable versionId,
            final String versionMessage) {
        if (isKioskEnabled()) {
            throw new RuntimeException(
                    Messages.getInstance().getString("JcrRepositoryFileDao.ERROR_0006_ACCESS_DENIED")); //$NON-NLS-1$
        }
        Assert.notNull(fileId);
        Assert.notNull(versionId);
        jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                Node fileNode = session.getNodeByIdentifier(fileId.toString());
                session.getWorkspace().getVersionManager().restore(fileNode.getPath(), versionId.toString(), true);
                return null;
            }
        });
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean canUnlockFile(final Serializable fileId) {
        return (Boolean) jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);
                Node fileNode = session.getNodeByIdentifier(fileId.toString());
                Lock lock = session.getWorkspace().getLockManager().getLock(fileNode.getPath());
                return lockHelper.canUnlock(session, pentahoJcrConstants, lock);
            }
        });
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public RepositoryFileTree getTree(final RepositoryRequest repositoryRequest) {
        Assert.hasText(repositoryRequest.getPath());
        return (RepositoryFileTree) jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);
                String absPath = pathConversionHelper.relToAbs(repositoryRequest.getPath());
                return JcrRepositoryFileUtils.getTree(session, pentahoJcrConstants, pathConversionHelper,
                        lockHelper, absPath, repositoryRequest, accessVoterManager);
            }
        });
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @Deprecated
    public RepositoryFileTree getTree(final String relPath, final int depth, final String filter,
            final boolean showHidden) {
        Assert.hasText(relPath);
        final RepositoryRequest repositoryRequest = new RepositoryRequest(relPath, showHidden, depth, filter);
        return (RepositoryFileTree) jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);
                String absPath = pathConversionHelper.relToAbs(relPath);
                return JcrRepositoryFileUtils.getTree(session, pentahoJcrConstants, pathConversionHelper,
                        lockHelper, absPath, repositoryRequest, accessVoterManager);
            }
        });
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<RepositoryFile> getReferrers(final Serializable fileId) {
        if (fileId == null) {
            return new ArrayList<RepositoryFile>();
        }

        return (List<RepositoryFile>) jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);

                Node fileNode = session.getNodeByIdentifier(fileId.toString());
                // guard against using a file retrieved from a more lenient session inside a more strict session
                Assert.notNull(fileNode);

                Set<RepositoryFile> referrers = new HashSet<RepositoryFile>();
                PropertyIterator refIter = fileNode.getReferences();
                if (refIter.hasNext()) {
                    while (refIter.hasNext()) {
                        // for each referrer property, march up the tree until we find the file node to which the property
                        // belongs
                        RepositoryFile referrer = getReferrerFile(session, pentahoJcrConstants,
                                refIter.nextProperty());
                        if (referrer != null) {
                            referrers.add(referrer);
                        }
                    }
                }
                session.save();
                return Arrays.asList(referrers.toArray());
            }
        });
    }

    protected RepositoryFile getReferrerFile(final Session session, final PentahoJcrConstants pentahoJcrConstants,
            final Property referrerProperty) throws RepositoryException {
        Node currentNode = referrerProperty.getParent();
        while (!currentNode.isNodeType(pentahoJcrConstants.getPHO_NT_PENTAHOHIERARCHYNODE())) {
            currentNode = currentNode.getParent();
        }
        // if folder, then referrer is a lock token record (under the user's home folder) which will be cleaned up by
        // lockHelper; ignore it
        if (currentNode.isNodeType(pentahoJcrConstants.getPHO_NT_PENTAHOFOLDER())) {
            return null;
        }

        return JcrRepositoryFileUtils.nodeToFile(session, pentahoJcrConstants, pathConversionHelper, lockHelper,
                currentNode);
    }

    @Override
    public void setFileMetadata(final Serializable fileId, final Map<String, Serializable> metadataMap) {
        if (isKioskEnabled()) {
            throw new RuntimeException(
                    Messages.getInstance().getString("JcrRepositoryFileDao.ERROR_0006_ACCESS_DENIED")); //$NON-NLS-1$
        }
        Assert.notNull(fileId);
        jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                JcrRepositoryFileUtils.setFileMetadata(session, fileId, metadataMap);
                return null;
            }
        });
    }

    @Override
    @SuppressWarnings("unchecked")
    public Map<String, Serializable> getFileMetadata(final Serializable fileId) {
        Assert.notNull(fileId);
        return (Map<String, Serializable>) jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(Session session) throws IOException, RepositoryException {
                return JcrRepositoryFileUtils.getFileMetadata(session, fileId);
            }
        });
    }

    @Override
    public List<Character> getReservedChars() {
        return JcrRepositoryFileUtils.getReservedChars();
    }

    public IRepositoryDefaultAclHandler getDefaultAclHandler() {
        return defaultAclHandler;
    }

    public void setDefaultAclHandler(IRepositoryDefaultAclHandler defaultAclHandler) {
        this.defaultAclHandler = defaultAclHandler;
    }

    @Override
    public List<Locale> getAvailableLocalesForFileById(Serializable fileId) {
        RepositoryFile repositoryFile = getFileById(fileId, true);
        return getAvailableLocalesForFile(repositoryFile);
    }

    @Override
    public List<Locale> getAvailableLocalesForFileByPath(String relPath) {
        RepositoryFile repositoryFile = getFileById(relPath, true);
        return getAvailableLocalesForFile(repositoryFile);
    }

    @Override
    public List<Locale> getAvailableLocalesForFile(RepositoryFile repositoryFile) {
        List<Locale> localeList = new ArrayList<Locale>();
        if (repositoryFile != null && repositoryFile.getLocalePropertiesMap() != null) {
            for (String localeName : repositoryFile.getLocalePropertiesMap().keySet()) {
                String[] localePieces = localeName.split("_");
                String language = localePieces[0];
                String country = (localePieces.length > 1) ? localePieces[1] : "";
                String variant = (localePieces.length > 2) ? localePieces[2] : "";
                Locale locale = new Locale(language, country, variant);
                localeList.add(locale);
            }
        }

        return localeList;
    }

    @Override
    public Properties getLocalePropertiesForFileById(Serializable fileId, String locale) {
        RepositoryFile repositoryFile = getFileById(fileId, true);
        return getLocalePropertiesForFile(repositoryFile, locale);
    }

    @Override
    public Properties getLocalePropertiesForFileByPath(String relPath, String locale) {

        RepositoryFile repositoryFile = getFileById(relPath, true);
        return getLocalePropertiesForFile(repositoryFile, locale);
    }

    @Override
    public Properties getLocalePropertiesForFile(RepositoryFile repositoryFile, String locale) {
        if (org.apache.commons.lang.StringUtils.isBlank(locale)) {
            locale = RepositoryFile.DEFAULT_LOCALE;
        }
        if (repositoryFile != null && repositoryFile.getLocalePropertiesMap() != null) {
            Properties properties = repositoryFile.getLocalePropertiesMap().get(locale);
            return properties;
        }

        return null;
    }

    @Override
    public void setLocalePropertiesForFileById(Serializable fileId, String locale, Properties properties) {
        if (isKioskEnabled()) {
            throw new RuntimeException(
                    Messages.getInstance().getString("JcrRepositoryFileDao.ERROR_0006_ACCESS_DENIED")); //$NON-NLS-1$
        }

        RepositoryFile repositoryFile = getFileById(fileId, true);
        setLocalePropertiesForFile(repositoryFile, locale, properties);
    }

    @Override
    public void setLocalePropertiesForFileByPath(String relPath, String locale, Properties properties) {
        if (isKioskEnabled()) {
            throw new RuntimeException(
                    Messages.getInstance().getString("JcrRepositoryFileDao.ERROR_0006_ACCESS_DENIED")); //$NON-NLS-1$
        }

        RepositoryFile repositoryFile = getFileById(relPath, true);
        setLocalePropertiesForFile(repositoryFile, locale, properties);
    }

    @Override
    public void setLocalePropertiesForFile(final RepositoryFile repositoryFile, final String locale,
            final Properties properties) {
        if (isKioskEnabled()) {
            throw new RuntimeException(
                    Messages.getInstance().getString("JcrRepositoryFileDao.ERROR_0006_ACCESS_DENIED")); //$NON-NLS-1$
        }

        Assert.notNull(repositoryFile);
        Assert.notNull(locale);
        Assert.notNull(properties);
        jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);
                String versionMessage = Messages.getInstance()
                        .getString("JcrRepositoryFileDao.LOCALE_0001_UPDATE_PROPERTIES", repositoryFile.getId());
                lockHelper.addLockTokenToSessionIfNecessary(session, pentahoJcrConstants, repositoryFile.getId());
                JcrRepositoryFileUtils.checkoutNearestVersionableFileIfNecessary(session, pentahoJcrConstants,
                        repositoryFile.getId());
                JcrRepositoryFileUtils.updateFileLocaleProperties(session, repositoryFile.getId(), locale,
                        properties);
                session.save();
                JcrRepositoryFileUtils.checkinNearestVersionableFileIfNecessary(session, pentahoJcrConstants,
                        repositoryFile.getId(), versionMessage);
                lockHelper.removeLockTokenFromSessionIfNecessary(session, pentahoJcrConstants,
                        repositoryFile.getId());
                return null;
            }
        });
    }

    @Override
    public void deleteLocalePropertiesForFile(final RepositoryFile repositoryFile, final String locale) {
        if (isKioskEnabled()) {
            throw new RuntimeException(
                    Messages.getInstance().getString("JcrRepositoryFileDao.ERROR_0006_ACCESS_DENIED")); //$NON-NLS-1$
        }

        Assert.notNull(repositoryFile);
        Assert.notNull(locale);
        jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);
                String versionMessage = Messages.getInstance()
                        .getString("JcrRepositoryFileDao.LOCALE_0002_DELETE_PROPERTIES", repositoryFile.getId());
                lockHelper.addLockTokenToSessionIfNecessary(session, pentahoJcrConstants, repositoryFile.getId());
                JcrRepositoryFileUtils.checkoutNearestVersionableFileIfNecessary(session, pentahoJcrConstants,
                        repositoryFile.getId());
                JcrRepositoryFileUtils.deleteFileLocaleProperties(session, repositoryFile.getId(), locale);
                session.save();
                JcrRepositoryFileUtils.checkinNearestVersionableFileIfNecessary(session, pentahoJcrConstants,
                        repositoryFile.getId(), versionMessage);
                lockHelper.removeLockTokenFromSessionIfNecessary(session, pentahoJcrConstants,
                        repositoryFile.getId());
                return null;
            }
        });
    }

    @Override
    public RepositoryFile updateFolder(final RepositoryFile file, final String versionMessage) {
        if (isKioskEnabled()) {
            throw new RuntimeException(
                    Messages.getInstance().getString("JcrRepositoryFileDao.ERROR_0006_ACCESS_DENIED")); //$NON-NLS-1$
        }

        Assert.notNull(file);
        Assert.isTrue(file.isFolder());
        return (RepositoryFile) jcrTemplate.execute(new JcrCallback() {
            @Override
            public Object doInJcr(final Session session) throws RepositoryException, IOException {
                PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);
                return internalUpdateFolder(session, pentahoJcrConstants, file, versionMessage);
            }
        });
    }

    private String extractNameFromPath(String path) {
        int startIndex = path.lastIndexOf(RepositoryFile.SEPARATOR);
        if (startIndex >= 0) {
            int endIndex = path.indexOf('.', startIndex);
            if (endIndex > startIndex) {
                return path.substring(startIndex + 1, endIndex);
            }
        }
        return null;
    }

    private boolean isKioskEnabled() {
        if (PentahoSystem.getInitializedOK()) {
            return "true".equals(PentahoSystem.getSystemSetting("kiosk-mode", "false"));
        } else {
            return false;
        }
    }
}