/******************************************************************************* * 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 License along 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.math.BigInteger; import java.util.ArrayList; import java.util.Collections; import java.util.List; 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.PermissionService; import jp.aegif.nemaki.cmis.service.NavigationService; import jp.aegif.nemaki.model.Content; import jp.aegif.nemaki.model.Document; import jp.aegif.nemaki.model.Folder; import jp.aegif.nemaki.util.DataUtil; import jp.aegif.nemaki.util.constant.DomainType; import jp.aegif.nemaki.util.lock.ThreadLockService; import org.apache.chemistry.opencmis.commons.PropertyIds; import org.apache.chemistry.opencmis.commons.data.ExtensionsData; import org.apache.chemistry.opencmis.commons.data.ObjectData; import org.apache.chemistry.opencmis.commons.data.ObjectInFolderContainer; import org.apache.chemistry.opencmis.commons.data.ObjectInFolderData; import org.apache.chemistry.opencmis.commons.data.ObjectInFolderList; import org.apache.chemistry.opencmis.commons.data.ObjectList; import org.apache.chemistry.opencmis.commons.data.ObjectParentData; import org.apache.chemistry.opencmis.commons.data.PermissionMapping; import org.apache.chemistry.opencmis.commons.enums.BaseTypeId; import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships; import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectInFolderContainerImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectInFolderDataImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectInFolderListImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectParentDataImpl; import org.apache.chemistry.opencmis.commons.server.CallContext; import org.apache.chemistry.opencmis.commons.spi.Holder; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; public class NavigationServiceImpl implements NavigationService { private ContentService contentService; private ExceptionService exceptionService; private CompileService compileService; private PermissionService permissionService; private ThreadLockService threadLockService; @Override public ObjectInFolderList getChildren(CallContext callContext, String repositoryId, String folderId, String filter, String orderBy, Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter, Boolean includePathSegments, BigInteger maxItems, BigInteger skipCount, ExtensionsData extension, Holder<ObjectData> parentObjectData) { exceptionService.invalidArgumentRequiredString("folderId", folderId); Lock parentLock = threadLockService.getReadLock(repositoryId, folderId); try{ parentLock.lock(); // ////////////////// // General Exception // ////////////////// Folder folder = contentService.getFolder(repositoryId, folderId); exceptionService.invalidArgumentFolderId(folder, folderId); exceptionService.permissionDenied(callContext, repositoryId, PermissionMapping.CAN_GET_CHILDREN_FOLDER, folder); // ////////////////// // Body of the method // ////////////////// // Set ObjectData of parent folder for ObjectInfo ObjectData _parent = compileService.compileObjectData( callContext, repositoryId, folder, filter, includeAllowableActions, includeRelationships, renditionFilter, false); parentObjectData.setValue(_parent); return getChildrenInternal(callContext, repositoryId, folderId, filter, orderBy, includeAllowableActions, includeRelationships, renditionFilter, includePathSegments, maxItems, skipCount, false); }finally{ parentLock.unlock(); } } private ObjectInFolderList getChildrenInternal(CallContext callContext, String repositoryId, String folderId, String filter, String orderBy, Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter, Boolean includePathSegments, BigInteger maxItems, BigInteger skipCount, boolean folderOnly) { // Prepare ObjectInFolderListImpl result = new ObjectInFolderListImpl(); result.setObjects(new ArrayList<ObjectInFolderData>()); result.setHasMoreItems(false); // Build ObjectList List<Content> contents = contentService.getChildren(repositoryId, folderId); List<Lock> locks = threadLockService.readLocks(repositoryId, contents); try{ threadLockService.bulkLock(locks); contents = permissionService.getFiltered(callContext, repositoryId, contents); ObjectList ol = compileService.compileObjectDataList(callContext, repositoryId, contents, filter, includeAllowableActions, includeRelationships, renditionFilter, false, maxItems, skipCount, folderOnly, orderBy); // Build ObjectInFolderList for (ObjectData od : ol.getObjects()) { ObjectInFolderDataImpl objectInFolder = new ObjectInFolderDataImpl(); objectInFolder.setObject(od); if (includePathSegments) { String name = DataUtil.getStringProperty(od.getProperties(), PropertyIds.NAME); objectInFolder.setPathSegment(name); } result.getObjects().add(objectInFolder); } result.setNumItems(ol.getNumItems()); result.setHasMoreItems(ol.hasMoreItems()); return result; }finally{ threadLockService.bulkUnlock(locks); } } @Override public List<ObjectInFolderContainer> getDescendants( CallContext callContext, String repositoryId, String folderId, BigInteger depth, String filter, Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter, Boolean includePathSegment, boolean foldersOnly, ExtensionsData extension, Holder<ObjectData> anscestorObjectData) { exceptionService.invalidArgumentRequiredString("folderId", folderId); Lock parentLock = threadLockService.getReadLock(repositoryId, folderId); try{ parentLock.lock(); // ////////////////// // General Exception // ////////////////// Folder folder = contentService.getFolder(repositoryId, folderId); exceptionService.permissionDenied(callContext, repositoryId, PermissionMapping.CAN_GET_DESCENDENTS_FOLDER, folder); // ////////////////// // Specific Exception // ////////////////// exceptionService.invalidArgumentFolderId(folder, folderId); exceptionService.invalidArgumentDepth(depth); // ////////////////// // Body of the method // ////////////////// // check depth int d = (depth == null ? 2 : depth.intValue()); // set defaults if values not set boolean iaa = (includeAllowableActions == null ? false : includeAllowableActions.booleanValue()); boolean ips = (includePathSegment == null ? false : includePathSegment .booleanValue()); // Set ObjectData of the starting folder for ObjectInfo ObjectData _folder = compileService.compileObjectData( callContext, repositoryId, folder, filter, includeAllowableActions, includeRelationships, renditionFilter, false); anscestorObjectData.setValue(_folder); // get the tree. return getDescendantsInternal(callContext, repositoryId, _folder, filter, iaa, false, includeRelationships, null, ips, 0, d, foldersOnly); }finally{ parentLock.unlock(); } } private List<ObjectInFolderContainer> getDescendantsInternal( CallContext callContext, String repositoryId, ObjectData node, String filter, Boolean includeAllowableActions, Boolean includeAcl, IncludeRelationships includeRelationships, String renditionFilter, Boolean includePathSegments, int level, int maxLevels, boolean folderOnly) { List<ObjectInFolderContainer> childrenOfFolder = new ArrayList<ObjectInFolderContainer>(); // Check specified folderId is folder(if not, it's a leaf node) if (node.getBaseTypeId() != BaseTypeId.CMIS_FOLDER) { return childrenOfFolder; } String folderId = node.getId(); if (maxLevels == -1 || level < maxLevels) { ObjectInFolderList children = getChildrenInternal(callContext, repositoryId, folderId, filter, null, includeAllowableActions, includeRelationships, renditionFilter, includePathSegments, BigInteger.valueOf(Integer.MAX_VALUE), BigInteger.valueOf(0), folderOnly); childrenOfFolder = new ArrayList<ObjectInFolderContainer>(); if (null != children && CollectionUtils.isNotEmpty(children.getObjects())) { for (ObjectInFolderData child : children.getObjects()) { ObjectInFolderContainerImpl oifc = new ObjectInFolderContainerImpl(); List<ObjectInFolderContainer> subChildren = getDescendantsInternal( callContext, repositoryId, child.getObject(), filter, includeAllowableActions, includeAcl, includeRelationships, renditionFilter, includePathSegments, level + 1, maxLevels, folderOnly); oifc.setObject(child); if (CollectionUtils.isNotEmpty(subChildren)) oifc.setChildren(subChildren); childrenOfFolder.add(oifc); } } } return childrenOfFolder; } @Override public ObjectData getFolderParent(CallContext callContext, String repositoryId, String folderId, String filter) { exceptionService.invalidArgumentRequiredString("folderId", folderId); Lock childLock = threadLockService.getReadLock(repositoryId, folderId); try{ childLock.lock(); // ////////////////// // General Exception // ////////////////// Folder folder = (Folder) contentService.getContent(repositoryId, folderId); exceptionService.objectNotFound(DomainType.OBJECT, folder, folderId); exceptionService.permissionDenied(callContext, repositoryId, PermissionMapping.CAN_GET_FOLDER_PARENT_OBJECT, folder); // ////////////////// // Specific Exception // ////////////////// Folder parent = contentService.getParent(repositoryId, folderId); Lock parentLock = threadLockService.getReadLock(repositoryId, parent.getId()); try{ parentLock.lock(); exceptionService.objectNotFoundParentFolder(repositoryId, folderId, parent); exceptionService.invalidArgumentRootFolder(repositoryId, folder); // ////////////////// // Body of the method // ////////////////// return compileService.compileObjectData(callContext, repositoryId, parent, filter, true, IncludeRelationships.NONE, null, true); }finally{ parentLock.unlock(); } }finally{ childLock.unlock(); } } @Override public List<ObjectParentData> getObjectParents(CallContext callContext, String repositoryId, String objectId, String filter, Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter, Boolean includeRelativePathSegment, ExtensionsData extension) { exceptionService.invalidArgumentRequired("objectId", objectId); Lock childLock = threadLockService.getReadLock(repositoryId, objectId); try{ childLock.lock(); // ////////////////// // General Exception // ////////////////// Content content = contentService.getContent(repositoryId, objectId); exceptionService.objectNotFound(DomainType.OBJECT, content, objectId); exceptionService.permissionDenied(callContext, repositoryId, PermissionMapping.CAN_GET_PARENTS_FOLDER, content); //Get parent Folder parent = contentService.getParent(repositoryId, objectId); Lock parentLock = threadLockService.getReadLock(repositoryId, parent.getId()); try{ parentLock.lock(); // ////////////////// // Specific Exception // ////////////////// exceptionService.objectNotFoundParentFolder(repositoryId, objectId, parent); exceptionService.invalidArgumentRootFolder(repositoryId, content); // ////////////////// // Body of the method // ////////////////// ObjectParentDataImpl result = new ObjectParentDataImpl(); ObjectData o = compileService.compileObjectData(callContext, repositoryId, parent, filter, includeAllowableActions, includeRelationships, null, true); result.setObject(o); boolean irps = (includeRelativePathSegment == null ? false : includeRelativePathSegment.booleanValue()); if (irps) { result.setRelativePathSegment(content.getName()); } return Collections.singletonList((ObjectParentData) result); }finally{ parentLock.unlock(); } }finally{ childLock.unlock(); } } @Override public ObjectList getCheckedOutDocs(CallContext callContext, String repositoryId, String folderId, String filter, String orderBy, Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter, BigInteger maxItems, BigInteger skipCount, ExtensionsData extension) { // ////////////////// // General Exception // ////////////////// // NONE // ////////////////// // Specific Exception // ////////////////// //Folder ID can be null, which means all PWCs are returned. if(StringUtils.isNotBlank(folderId)){ Folder folder = contentService.getFolder(repositoryId, folderId); exceptionService.objectNotFoundParentFolder(repositoryId, folderId, folder); } exceptionService.invalidArgumentOrderBy(repositoryId, orderBy); // ////////////////// // Body of the method // ////////////////// //Folder ID can be null, which means all PWCs are returned. List<Document> checkedOuts = contentService.getCheckedOutDocs(repositoryId, folderId, orderBy, extension); List<Lock> locks = threadLockService.readLocks(repositoryId, checkedOuts); try{ threadLockService.bulkLock(locks); ObjectList list = compileService.compileObjectDataList( callContext, repositoryId, checkedOuts, filter, includeAllowableActions, includeRelationships, renditionFilter, false, maxItems, skipCount, false, orderBy); return list; }finally{ threadLockService.bulkUnlock(locks); } } public void setContentService(ContentService contentService) { this.contentService = contentService; } public void setExceptionService(ExceptionService exceptionService) { this.exceptionService = exceptionService; } public void setCompileService(CompileService compileService) { this.compileService = compileService; } public void setPermissionService(PermissionService permissionService) { this.permissionService = permissionService; } public void setThreadLockService(ThreadLockService threadLockService) { this.threadLockService = threadLockService; } }