jp.aegif.nemaki.cmis.service.impl.AclServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for jp.aegif.nemaki.cmis.service.impl.AclServiceImpl.java

Source

/*******************************************************************************
 * Copyright (c) 2013 aegif.
 *
 * This file is part of NemakiWare.
 *
 * NemakiWare is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * NemakiWare 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.
 *
 * You should have received a copy of the GNU General Public Licensealong with NemakiWare. If not, see <http://www.gnu.org/licenses/>.
 *
 * Contributors:
 *     linzhixing(https://github.com/linzhixing) - initial API and implementation
 ******************************************************************************/
package jp.aegif.nemaki.cmis.service.impl;

import java.util.List;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;

import jp.aegif.nemaki.businesslogic.ContentService;
import jp.aegif.nemaki.cmis.aspect.CompileService;
import jp.aegif.nemaki.cmis.aspect.ExceptionService;
import jp.aegif.nemaki.cmis.aspect.type.TypeManager;
import jp.aegif.nemaki.cmis.factory.info.RepositoryInfo;
import jp.aegif.nemaki.cmis.factory.info.RepositoryInfoMap;
import jp.aegif.nemaki.cmis.service.AclService;
import jp.aegif.nemaki.model.Content;
import jp.aegif.nemaki.util.cache.NemakiCachePool;
import jp.aegif.nemaki.util.constant.DomainType;
import jp.aegif.nemaki.util.constant.PrincipalId;
import jp.aegif.nemaki.util.lock.ThreadLockService;

import org.apache.chemistry.opencmis.commons.data.Ace;
import org.apache.chemistry.opencmis.commons.data.Acl;
import org.apache.chemistry.opencmis.commons.data.CmisExtensionElement;
import org.apache.chemistry.opencmis.commons.data.PermissionMapping;
import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
import org.apache.chemistry.opencmis.commons.enums.AclPropagation;
import org.apache.chemistry.opencmis.commons.enums.ChangeType;
import org.apache.chemistry.opencmis.commons.server.CallContext;
import org.apache.commons.collections.CollectionUtils;

/**
 * Discovery Service implementation for CouchDB.
 *
 */
public class AclServiceImpl implements AclService {

    private ContentService contentService;
    private CompileService compileService;
    private ExceptionService exceptionService;
    private TypeManager typeManager;
    private ThreadLockService threadLockService;
    private NemakiCachePool nemakiCachePool;
    private RepositoryInfoMap repositoryInfoMap;

    @Override
    public Acl getAcl(CallContext callContext, String repositoryId, String objectId, Boolean onlyBasicPermissions) {

        exceptionService.invalidArgumentRequired("objectId", objectId);

        Lock lock = threadLockService.getReadLock(repositoryId, objectId);

        try {
            lock.lock();

            // //////////////////
            // General Exception
            // //////////////////

            Content content = contentService.getContent(repositoryId, objectId);
            exceptionService.objectNotFound(DomainType.OBJECT, content, objectId);
            exceptionService.permissionDenied(callContext, repositoryId, PermissionMapping.CAN_GET_ACL_OBJECT,
                    content);

            // //////////////////
            // Body of the method
            // //////////////////
            jp.aegif.nemaki.model.Acl acl = contentService.calculateAcl(repositoryId, content);
            //return compileService.compileAcl(acl, content.isAclInherited(), onlyBasicPermissions);
            return compileService.compileAcl(acl, contentService.getAclInheritedWithDefault(repositoryId, content),
                    onlyBasicPermissions);
        } finally {
            lock.unlock();
        }
    }

    @Override
    public Acl applyAcl(CallContext callContext, String repositoryId, String objectId, Acl acl,
            AclPropagation aclPropagation) {
        exceptionService.invalidArgumentRequired("objectId", objectId);

        Lock lock = threadLockService.getReadLock(repositoryId, objectId);

        try {
            lock.lock();

            // //////////////////
            // General Exception
            // //////////////////

            Content content = contentService.getContent(repositoryId, objectId);
            exceptionService.objectNotFound(DomainType.OBJECT, content, objectId);
            exceptionService.permissionDenied(callContext, repositoryId, PermissionMapping.CAN_APPLY_ACL_OBJECT,
                    content);

            // //////////////////
            // Specific Exception
            // //////////////////
            TypeDefinition td = typeManager.getTypeDefinition(repositoryId, content);
            if (!td.isControllableAcl())
                exceptionService.constraint(objectId,
                        "applyAcl cannot be performed on the object whose controllableAcl = false");
            exceptionService.constraintAclPropagationDoesNotMatch(aclPropagation);
            exceptionService.constraintPermissionDefined(repositoryId, acl, objectId);

            // //////////////////
            // Body of the method
            // //////////////////
            //Check ACL inheritance
            boolean inherited = true; //Inheritance defaults to true if nothing input
            List<CmisExtensionElement> exts = acl.getExtensions();
            if (!CollectionUtils.isEmpty(exts)) {
                for (CmisExtensionElement ext : exts) {
                    if (ext.getName().equals("inherited")) {
                        inherited = Boolean.valueOf(ext.getValue());
                    }
                }
                if (!contentService.getAclInheritedWithDefault(repositoryId, content).equals(inherited))
                    content.setAclInherited(inherited);
            }

            jp.aegif.nemaki.model.Acl nemakiAcl = new jp.aegif.nemaki.model.Acl();
            //REPOSITORYDETERMINED or PROPAGATE is considered as PROPAGATE
            boolean objectOnly = (aclPropagation == AclPropagation.OBJECTONLY) ? true : false;
            for (Ace ace : acl.getAces()) {
                if (ace.isDirect()) {
                    jp.aegif.nemaki.model.Ace nemakiAce = new jp.aegif.nemaki.model.Ace(ace.getPrincipalId(),
                            ace.getPermissions(), objectOnly);
                    nemakiAcl.getLocalAces().add(nemakiAce);
                }
            }

            convertSystemPrinciaplId(repositoryId, nemakiAcl);
            content.setAcl(nemakiAcl);
            contentService.update(repositoryId, content);
            contentService.writeChangeEvent(callContext, repositoryId, content, nemakiAcl, ChangeType.SECURITY);

            nemakiCachePool.get(repositoryId).removeCmisCache(objectId);

            clearCachesRecursively(Executors.newCachedThreadPool(), callContext, repositoryId, content, false);
            writeChangeEventsRecursively(Executors.newCachedThreadPool(), callContext, repositoryId, content,
                    false);

            return getAcl(callContext, repositoryId, objectId, false);
        } finally {
            lock.unlock();
        }

    }

    private void clearCachesRecursively(ExecutorService executorService, CallContext callContext,
            final String repositoryId, Content content, boolean executeOnParent) {

        //Call threads for recursive applyAcl
        if (content.isFolder()) {
            List<Content> children = contentService.getChildren(repositoryId, content.getId());
            if (CollectionUtils.isEmpty(children)) {
                return;
            }

            if (executeOnParent) {
                executorService.submit(new ClearCacheTask(repositoryId, content.getId()));
            }
            for (Content child : children) {
                if (contentService.getAclInheritedWithDefault(repositoryId, child)) {
                    executorService.submit(
                            new ClearCachesRecursivelyTask(executorService, callContext, repositoryId, child));
                }
            }
        } else {
            executorService.submit(new ClearCacheTask(repositoryId, content.getId()));
        }
    }

    private class ClearCacheTask implements Runnable {
        private String repositoryId;
        private String objectId;

        public ClearCacheTask(String repositoryId, String objectId) {
            super();
            this.repositoryId = repositoryId;
            this.objectId = objectId;
        }

        @Override
        public void run() {
            // TODO Auto-generated method stub
            nemakiCachePool.get(repositoryId).removeCmisAndContentCache(objectId);
        }
    }

    private class ClearCachesRecursivelyTask implements Runnable {
        private ExecutorService executorService;
        private CallContext callContext;
        private String repositoryId;
        private Content content;

        public ClearCachesRecursivelyTask(ExecutorService executorService, CallContext callContext,
                String repositoryId, Content content) {
            super();
            this.executorService = executorService;
            this.callContext = callContext;
            this.repositoryId = repositoryId;
            this.content = content;
        }

        @Override
        public void run() {
            clearCachesRecursively(executorService, callContext, repositoryId, content, true);
        }
    }

    private void writeChangeEventsRecursively(ExecutorService executorService, CallContext callContext,
            final String repositoryId, Content content, boolean executeOnParent) {

        //Call threads for recursive applyAcl
        if (content.isFolder()) {
            List<Content> children = contentService.getChildren(repositoryId, content.getId());
            if (CollectionUtils.isEmpty(children)) {
                return;
            }

            if (executeOnParent) {
                executorService.submit(new ClearCacheTask(repositoryId, content.getId()));
            }
            for (Content child : children) {
                if (contentService.getAclInheritedWithDefault(repositoryId, child)) {
                    executorService.submit(new WriteChangeEventsRecursivelyTask(executorService, callContext,
                            repositoryId, child));
                }
            }
        } else {
            executorService.submit(new WriteChangeEventTask(callContext, repositoryId, content));
        }
    }

    private class WriteChangeEventTask implements Runnable {
        private CallContext callContext;
        private String repositoryId;
        private Content content;

        public WriteChangeEventTask(CallContext callContext, String repositoryId, Content content) {
            super();
            this.callContext = callContext;
            this.repositoryId = repositoryId;
            this.content = content;
        }

        @Override
        public void run() {
            // TODO content.getAcl()? content.calculateAcl()?
            contentService.writeChangeEvent(callContext, repositoryId, content, content.getAcl(),
                    ChangeType.SECURITY);
        }
    }

    private class WriteChangeEventsRecursivelyTask implements Runnable {
        private ExecutorService executorService;
        private CallContext callContext;
        private String repositoryId;
        private Content content;

        public WriteChangeEventsRecursivelyTask(ExecutorService executorService, CallContext callContext,
                String repositoryId, Content content) {
            super();
            this.executorService = executorService;
            this.callContext = callContext;
            this.repositoryId = repositoryId;
            this.content = content;
        }

        @Override
        public void run() {
            writeChangeEventsRecursively(executorService, callContext, repositoryId, content, true);
        }
    }

    private void convertSystemPrinciaplId(String repositoryId, jp.aegif.nemaki.model.Acl acl) {
        List<jp.aegif.nemaki.model.Ace> aces = acl.getAllAces();
        for (jp.aegif.nemaki.model.Ace ace : aces) {
            RepositoryInfo info = repositoryInfoMap.get(repositoryId);

            //Convert anonymous to the form of database
            String anonymous = info.getPrincipalIdAnonymous();
            if (anonymous.equals(ace.getPrincipalId())) {
                ace.setPrincipalId(PrincipalId.ANONYMOUS_IN_DB);
            }

            //Convert anyone to the form of database
            String anyone = info.getPrincipalIdAnyone();
            if (anyone.equals(ace.getPrincipalId())) {
                ace.setPrincipalId(PrincipalId.ANYONE_IN_DB);

            }
        }
    }

    public void setContentService(ContentService contentService) {
        this.contentService = contentService;
    }

    public void setExceptionService(ExceptionService exceptionService) {
        this.exceptionService = exceptionService;
    }

    public void setTypeManager(TypeManager typeManager) {
        this.typeManager = typeManager;
    }

    public void setThreadLockService(ThreadLockService threadLockService) {
        this.threadLockService = threadLockService;
    }

    public void setNemakiCachePool(NemakiCachePool nemakiCachePool) {
        this.nemakiCachePool = nemakiCachePool;
    }

    public void setCompileService(CompileService compileService) {
        this.compileService = compileService;
    }

    public void setRepositoryInfoMap(RepositoryInfoMap repositoryInfoMap) {
        this.repositoryInfoMap = repositoryInfoMap;
    }
}