mirror of
				https://github.com/Alfresco/alfresco-community-repo.git
				synced 2025-10-29 15:21:53 +00:00 
			
		
		
		
	109077: Merged V4.2-BUG-FIX (4.2.6) to 5.0.N (5.0.3)
      108983: MNT-9839: CMIS TCK Failures: Fix for hundreds of warnings regarding missing ACL exact flag in atom binding.
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@109146 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
		
	
		
			
				
	
	
		
			4205 lines
		
	
	
		
			148 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			4205 lines
		
	
	
		
			148 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| /*
 | |
|  * Copyright (C) 2005-2014 Alfresco Software Limited.
 | |
|  *
 | |
|  * This file is part of Alfresco
 | |
|  *
 | |
|  * Alfresco 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 3 of the License, or
 | |
|  * (at your option) any later version.
 | |
|  *
 | |
|  * Alfresco 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.
 | |
|  *
 | |
|  * You should have received a copy of the GNU Lesser General Public License
 | |
|  * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | |
|  */
 | |
| package org.alfresco.opencmis;
 | |
| 
 | |
| import java.io.BufferedOutputStream;
 | |
| import java.io.File;
 | |
| import java.io.IOException;
 | |
| import java.io.InputStream;
 | |
| import java.io.OutputStream;
 | |
| import java.io.SequenceInputStream;
 | |
| import java.io.Serializable;
 | |
| import java.math.BigDecimal;
 | |
| import java.math.BigInteger;
 | |
| import java.util.ArrayList;
 | |
| import java.util.Arrays;
 | |
| import java.util.Collections;
 | |
| import java.util.Comparator;
 | |
| import java.util.Date;
 | |
| import java.util.EnumSet;
 | |
| import java.util.GregorianCalendar;
 | |
| import java.util.HashMap;
 | |
| import java.util.HashSet;
 | |
| import java.util.Iterator;
 | |
| import java.util.List;
 | |
| import java.util.Map;
 | |
| import java.util.Map.Entry;
 | |
| import java.util.Set;
 | |
| import java.util.TimeZone;
 | |
| import java.util.TreeSet;
 | |
| 
 | |
| import javax.xml.datatype.DatatypeConfigurationException;
 | |
| import javax.xml.datatype.DatatypeFactory;
 | |
| 
 | |
| import org.alfresco.error.AlfrescoRuntimeException;
 | |
| import org.alfresco.events.types.ContentEvent;
 | |
| import org.alfresco.events.types.ContentEventImpl;
 | |
| import org.alfresco.events.types.ContentReadRangeEvent;
 | |
| import org.alfresco.events.types.Event;
 | |
| import org.alfresco.model.ContentModel;
 | |
| import org.alfresco.opencmis.ActivityPosterImpl.ActivityInfo;
 | |
| import org.alfresco.opencmis.dictionary.CMISActionEvaluator;
 | |
| import org.alfresco.opencmis.dictionary.CMISAllowedActionEnum;
 | |
| import org.alfresco.opencmis.dictionary.CMISDictionaryService;
 | |
| import org.alfresco.opencmis.dictionary.CMISNodeInfo;
 | |
| import org.alfresco.opencmis.dictionary.CMISObjectVariant;
 | |
| import org.alfresco.opencmis.dictionary.CMISPropertyAccessor;
 | |
| import org.alfresco.opencmis.dictionary.DocumentTypeDefinitionWrapper;
 | |
| import org.alfresco.opencmis.dictionary.FolderTypeDefintionWrapper;
 | |
| import org.alfresco.opencmis.dictionary.ItemTypeDefinitionWrapper;
 | |
| import org.alfresco.opencmis.dictionary.PropertyDefinitionWrapper;
 | |
| import org.alfresco.opencmis.dictionary.TypeDefinitionWrapper;
 | |
| import org.alfresco.opencmis.mapping.DirectProperty;
 | |
| import org.alfresco.opencmis.search.CMISQueryOptions;
 | |
| import org.alfresco.opencmis.search.CMISQueryOptions.CMISQueryMode;
 | |
| import org.alfresco.opencmis.search.CMISQueryService;
 | |
| import org.alfresco.opencmis.search.CMISResultSet;
 | |
| import org.alfresco.opencmis.search.CMISResultSetColumn;
 | |
| import org.alfresco.opencmis.search.CMISResultSetRow;
 | |
| import org.alfresco.query.PagingRequest;
 | |
| import org.alfresco.query.PagingResults;
 | |
| import org.alfresco.repo.Client;
 | |
| import org.alfresco.repo.Client.ClientType;
 | |
| import org.alfresco.repo.action.executer.ContentMetadataExtracter;
 | |
| import org.alfresco.repo.cache.SimpleCache;
 | |
| import org.alfresco.repo.dictionary.DictionaryDAO;
 | |
| import org.alfresco.repo.dictionary.DictionaryListener;
 | |
| import org.alfresco.repo.events.EventPreparator;
 | |
| import org.alfresco.repo.events.EventPublisher;
 | |
| import org.alfresco.repo.model.filefolder.GetChildrenCannedQuery;
 | |
| import org.alfresco.repo.model.filefolder.HiddenAspect;
 | |
| import org.alfresco.repo.model.filefolder.HiddenAspect.Visibility;
 | |
| import org.alfresco.repo.policy.BehaviourFilter;
 | |
| import org.alfresco.repo.security.authentication.AuthenticationUtil;
 | |
| import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
 | |
| import org.alfresco.repo.security.permissions.AccessDeniedException;
 | |
| import org.alfresco.repo.security.permissions.PermissionReference;
 | |
| import org.alfresco.repo.security.permissions.impl.AccessPermissionImpl;
 | |
| import org.alfresco.repo.security.permissions.impl.ModelDAO;
 | |
| import org.alfresco.repo.tenant.TenantAdminService;
 | |
| import org.alfresco.repo.tenant.TenantDeployer;
 | |
| import org.alfresco.repo.thumbnail.ThumbnailDefinition;
 | |
| import org.alfresco.repo.thumbnail.ThumbnailHelper;
 | |
| import org.alfresco.repo.thumbnail.ThumbnailRegistry;
 | |
| import org.alfresco.repo.transaction.RetryingTransactionHelper;
 | |
| import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
 | |
| import org.alfresco.repo.version.VersionBaseModel;
 | |
| import org.alfresco.repo.version.VersionModel;
 | |
| import org.alfresco.service.ServiceRegistry;
 | |
| import org.alfresco.service.cmr.action.ActionService;
 | |
| import org.alfresco.service.cmr.audit.AuditQueryParameters;
 | |
| import org.alfresco.service.cmr.audit.AuditService;
 | |
| import org.alfresco.service.cmr.audit.AuditService.AuditQueryCallback;
 | |
| import org.alfresco.service.cmr.coci.CheckOutCheckInService;
 | |
| import org.alfresco.service.cmr.dictionary.AspectDefinition;
 | |
| import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
 | |
| import org.alfresco.service.cmr.dictionary.DictionaryService;
 | |
| import org.alfresco.service.cmr.dictionary.InvalidAspectException;
 | |
| import org.alfresco.service.cmr.lock.LockService;
 | |
| import org.alfresco.service.cmr.model.FileExistsException;
 | |
| import org.alfresco.service.cmr.model.FileFolderService;
 | |
| import org.alfresco.service.cmr.model.FileInfo;
 | |
| import org.alfresco.service.cmr.model.FileNotFoundException;
 | |
| import org.alfresco.service.cmr.rendition.RenditionService;
 | |
| import org.alfresco.service.cmr.repository.AssociationRef;
 | |
| import org.alfresco.service.cmr.repository.ChildAssociationRef;
 | |
| import org.alfresco.service.cmr.repository.ContentData;
 | |
| import org.alfresco.service.cmr.repository.ContentReader;
 | |
| import org.alfresco.service.cmr.repository.ContentService;
 | |
| import org.alfresco.service.cmr.repository.ContentWriter;
 | |
| import org.alfresco.service.cmr.repository.InvalidNodeRefException;
 | |
| import org.alfresco.service.cmr.repository.MimetypeService;
 | |
| import org.alfresco.service.cmr.repository.NodeRef;
 | |
| import org.alfresco.service.cmr.repository.NodeService;
 | |
| import org.alfresco.service.cmr.repository.Path;
 | |
| import org.alfresco.service.cmr.repository.Path.ChildAssocElement;
 | |
| import org.alfresco.service.cmr.repository.StoreRef;
 | |
| import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
 | |
| import org.alfresco.service.cmr.search.SearchService;
 | |
| import org.alfresco.service.cmr.security.AccessPermission;
 | |
| import org.alfresco.service.cmr.security.AccessStatus;
 | |
| import org.alfresco.service.cmr.security.AuthenticationService;
 | |
| import org.alfresco.service.cmr.security.PermissionService;
 | |
| import org.alfresco.service.cmr.site.SiteInfo;
 | |
| import org.alfresco.service.cmr.site.SiteService;
 | |
| import org.alfresco.service.cmr.thumbnail.ThumbnailService;
 | |
| import org.alfresco.service.cmr.version.VersionHistory;
 | |
| import org.alfresco.service.cmr.version.VersionService;
 | |
| import org.alfresco.service.cmr.version.VersionType;
 | |
| import org.alfresco.service.descriptor.Descriptor;
 | |
| import org.alfresco.service.descriptor.DescriptorService;
 | |
| import org.alfresco.service.namespace.NamespaceService;
 | |
| import org.alfresco.service.namespace.QName;
 | |
| import org.alfresco.service.namespace.RegexQNamePattern;
 | |
| import org.alfresco.service.transaction.TransactionService;
 | |
| import org.alfresco.util.FileFilterMode;
 | |
| import org.alfresco.util.Pair;
 | |
| import org.alfresco.util.TempFileProvider;
 | |
| import org.apache.chemistry.opencmis.commons.BasicPermissions;
 | |
| import org.apache.chemistry.opencmis.commons.PropertyIds;
 | |
| import org.apache.chemistry.opencmis.commons.data.Ace;
 | |
| import org.apache.chemistry.opencmis.commons.data.Acl;
 | |
| import org.apache.chemistry.opencmis.commons.data.AllowableActions;
 | |
| import org.apache.chemistry.opencmis.commons.data.CmisExtensionElement;
 | |
| import org.apache.chemistry.opencmis.commons.data.ContentStream;
 | |
| import org.apache.chemistry.opencmis.commons.data.ObjectData;
 | |
| import org.apache.chemistry.opencmis.commons.data.ObjectList;
 | |
| import org.apache.chemistry.opencmis.commons.data.PermissionMapping;
 | |
| import org.apache.chemistry.opencmis.commons.data.Properties;
 | |
| import org.apache.chemistry.opencmis.commons.data.PropertyData;
 | |
| import org.apache.chemistry.opencmis.commons.data.PropertyId;
 | |
| import org.apache.chemistry.opencmis.commons.data.PropertyString;
 | |
| import org.apache.chemistry.opencmis.commons.data.RenditionData;
 | |
| import org.apache.chemistry.opencmis.commons.data.RepositoryInfo;
 | |
| import org.apache.chemistry.opencmis.commons.definitions.DocumentTypeDefinition;
 | |
| import org.apache.chemistry.opencmis.commons.definitions.PermissionDefinition;
 | |
| import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition;
 | |
| import org.apache.chemistry.opencmis.commons.enums.AclPropagation;
 | |
| import org.apache.chemistry.opencmis.commons.enums.Action;
 | |
| import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
 | |
| import org.apache.chemistry.opencmis.commons.enums.CapabilityAcl;
 | |
| import org.apache.chemistry.opencmis.commons.enums.CapabilityChanges;
 | |
| import org.apache.chemistry.opencmis.commons.enums.CapabilityContentStreamUpdates;
 | |
| import org.apache.chemistry.opencmis.commons.enums.CapabilityJoin;
 | |
| import org.apache.chemistry.opencmis.commons.enums.CapabilityQuery;
 | |
| import org.apache.chemistry.opencmis.commons.enums.CapabilityRenditions;
 | |
| import org.apache.chemistry.opencmis.commons.enums.Cardinality;
 | |
| import org.apache.chemistry.opencmis.commons.enums.ChangeType;
 | |
| import org.apache.chemistry.opencmis.commons.enums.CmisVersion;
 | |
| import org.apache.chemistry.opencmis.commons.enums.ContentStreamAllowed;
 | |
| import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
 | |
| import org.apache.chemistry.opencmis.commons.enums.PropertyType;
 | |
| import org.apache.chemistry.opencmis.commons.enums.RelationshipDirection;
 | |
| import org.apache.chemistry.opencmis.commons.enums.SupportedPermissions;
 | |
| import org.apache.chemistry.opencmis.commons.enums.Updatability;
 | |
| import org.apache.chemistry.opencmis.commons.enums.VersioningState;
 | |
| import org.apache.chemistry.opencmis.commons.exceptions.CmisBaseException;
 | |
| import org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException;
 | |
| import org.apache.chemistry.opencmis.commons.exceptions.CmisContentAlreadyExistsException;
 | |
| import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
 | |
| import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
 | |
| import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
 | |
| import org.apache.chemistry.opencmis.commons.exceptions.CmisStreamNotSupportedException;
 | |
| import org.apache.chemistry.opencmis.commons.impl.dataobjects.AbstractPropertyData;
 | |
| import org.apache.chemistry.opencmis.commons.impl.dataobjects.AccessControlEntryImpl;
 | |
| import org.apache.chemistry.opencmis.commons.impl.dataobjects.AccessControlListImpl;
 | |
| import org.apache.chemistry.opencmis.commons.impl.dataobjects.AccessControlPrincipalDataImpl;
 | |
| import org.apache.chemistry.opencmis.commons.impl.dataobjects.AclCapabilitiesDataImpl;
 | |
| import org.apache.chemistry.opencmis.commons.impl.dataobjects.AllowableActionsImpl;
 | |
| import org.apache.chemistry.opencmis.commons.impl.dataobjects.ChangeEventInfoDataImpl;
 | |
| import org.apache.chemistry.opencmis.commons.impl.dataobjects.CmisExtensionElementImpl;
 | |
| import org.apache.chemistry.opencmis.commons.impl.dataobjects.ContentStreamImpl;
 | |
| import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectDataImpl;
 | |
| import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectListImpl;
 | |
| import org.apache.chemistry.opencmis.commons.impl.dataobjects.PermissionDefinitionDataImpl;
 | |
| import org.apache.chemistry.opencmis.commons.impl.dataobjects.PermissionMappingDataImpl;
 | |
| import org.apache.chemistry.opencmis.commons.impl.dataobjects.PolicyIdListImpl;
 | |
| import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertiesImpl;
 | |
| import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyBooleanImpl;
 | |
| import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyDateTimeImpl;
 | |
| import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyDecimalImpl;
 | |
| import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyHtmlImpl;
 | |
| import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyIdImpl;
 | |
| import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyIntegerImpl;
 | |
| import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyStringImpl;
 | |
| import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyUriImpl;
 | |
| import org.apache.chemistry.opencmis.commons.impl.dataobjects.RepositoryCapabilitiesImpl;
 | |
| import org.apache.chemistry.opencmis.commons.impl.dataobjects.RepositoryInfoImpl;
 | |
| import org.apache.chemistry.opencmis.commons.server.CallContext;
 | |
| import org.apache.chemistry.opencmis.commons.server.CmisService;
 | |
| import org.apache.chemistry.opencmis.commons.spi.Holder;
 | |
| import org.apache.commons.io.IOUtils;
 | |
| import org.apache.commons.logging.Log;
 | |
| import org.apache.commons.logging.LogFactory;
 | |
| import org.springframework.beans.BeansException;
 | |
| import org.springframework.context.ApplicationContext;
 | |
| import org.springframework.context.ApplicationContextAware;
 | |
| import org.springframework.context.ApplicationEvent;
 | |
| import org.springframework.context.ApplicationListener;
 | |
| import org.springframework.context.event.ApplicationContextEvent;
 | |
| import org.springframework.extensions.surf.util.AbstractLifecycleBean;
 | |
| import org.springframework.util.StringUtils;
 | |
| 
 | |
| /**
 | |
|  * Bridge connecting Alfresco and OpenCMIS.
 | |
|  * <p/>
 | |
|  * This class  provides many of the typical services that the {@link CmisService} implementation
 | |
|  * will need to use Alfresco.
 | |
|  * 
 | |
|  * @author florian.mueller
 | |
|  * @author Derek Hulley
 | |
|  * @author steveglover
 | |
|  */
 | |
| public class CMISConnector implements ApplicationContextAware, ApplicationListener<ApplicationContextEvent>, TenantDeployer, DictionaryListener
 | |
| {
 | |
|     private static Log logger = LogFactory.getLog(CMISConnector.class);
 | |
| 
 | |
|     // mappings from cmis property names to their Alfresco property name counterparts (used by getChildren)
 | |
|     private static Map<String, QName> SORT_PROPERTY_MAPPINGS = new HashMap<String, QName>();
 | |
|     
 | |
|     static
 | |
|     {
 | |
|     	SORT_PROPERTY_MAPPINGS.put(PropertyIds.LAST_MODIFICATION_DATE, ContentModel.PROP_MODIFIED);
 | |
|     	SORT_PROPERTY_MAPPINGS.put(PropertyIds.CREATION_DATE, ContentModel.PROP_CREATED);
 | |
|     }
 | |
| 
 | |
|     public static final char ID_SEPERATOR = ';';
 | |
|     public static final String ASSOC_ID_PREFIX = "assoc:";
 | |
|     public static final String PWC_VERSION_LABEL = "pwc";
 | |
|     public static final String UNVERSIONED_VERSION_LABEL = "1.0";
 | |
| 
 | |
|     public static final String RENDITION_NONE = "cmis:none";
 | |
| 
 | |
|     public static final String CMIS_CHANGELOG_AUDIT_APPLICATION = "CMISChangeLog";
 | |
| 
 | |
|     public static final String ALFRESCO_EXTENSION_NAMESPACE = "http://www.alfresco.org";
 | |
|     public static final String CMIS_NAMESPACE = "http://docs.oasis-open.org/ns/cmis/core/200908/";
 | |
|     public static final String ASPECTS = "aspects";
 | |
|     public static final String SET_ASPECTS = "setAspects";
 | |
|     public static final String APPLIED_ASPECTS = "appliedAspects";
 | |
|     public static final String ASPECTS_TO_ADD = "aspectsToAdd";
 | |
|     public static final String ASPECTS_TO_REMOVE = "aspectsToRemove";
 | |
|     public static final String PROPERTIES = "properties";
 | |
| 
 | |
|     private static final BigInteger TYPES_DEFAULT_MAX_ITEMS = BigInteger.valueOf(50);
 | |
|     private static final BigInteger TYPES_DEFAULT_DEPTH = BigInteger.valueOf(-1);
 | |
|     private static final BigInteger OBJECTS_DEFAULT_MAX_ITEMS = BigInteger.valueOf(200);
 | |
|     private static final BigInteger OBJECTS_DEFAULT_DEPTH = BigInteger.valueOf(10);
 | |
| 
 | |
|     private static final String QUERY_NAME_OBJECT_ID = "cmis:objectId";
 | |
|     private static final String QUERY_NAME_OBJECT_TYPE_ID = "cmis:objectTypeId";
 | |
|     private static final String QUERY_NAME_BASE_TYPE_ID = "cmis:baseTypeId";
 | |
| 
 | |
|     private static final String CMIS_USER = "cmis:user";
 | |
| 
 | |
| 	private static final BigInteger maxInt = BigInteger.valueOf(Integer.MAX_VALUE);
 | |
| 	private static final BigInteger minInt = BigInteger.valueOf(Integer.MIN_VALUE);
 | |
| 	private static final BigInteger maxLong  = BigInteger.valueOf(Long.MAX_VALUE);
 | |
| 	private static final BigInteger minLong  = BigInteger.valueOf(Long.MIN_VALUE);
 | |
| 
 | |
|     // lifecycle
 | |
|     private ProcessorLifecycle lifecycle = new ProcessorLifecycle();
 | |
| 
 | |
|     // Alfresco objects
 | |
|     private DescriptorService descriptorService;
 | |
|     private NodeService nodeService;
 | |
|     private VersionService versionService;
 | |
|     private CheckOutCheckInService checkOutCheckInService;
 | |
|     private LockService lockService;
 | |
|     private ContentService contentService;
 | |
|     private RenditionService renditionService;
 | |
|     private FileFolderService fileFolderService;
 | |
|     private TenantAdminService tenantAdminService;
 | |
|     private TransactionService transactionService;
 | |
|     private AuthenticationService authenticationService;
 | |
|     private PermissionService permissionService;
 | |
|     private ModelDAO permissionModelDao;
 | |
|     private CMISDictionaryService cmisDictionaryService;
 | |
|     private CMISDictionaryService cmisDictionaryService11;
 | |
|     private CMISQueryService cmisQueryService;
 | |
|     private CMISQueryService cmisQueryService11;
 | |
|     private MimetypeService mimetypeService;
 | |
|     private AuditService auditService;
 | |
|     private NamespaceService namespaceService;
 | |
|     private SearchService searchService;
 | |
|     private DictionaryService dictionaryService;
 | |
|     private SiteService siteService;
 | |
|     private ActionService actionService;
 | |
|     private ThumbnailService thumbnailService;
 | |
|     private ServiceRegistry serviceRegistry;
 | |
|     private EventPublisher eventPublisher;
 | |
| 
 | |
|     private CmisActivityPoster activityPoster;
 | |
| 
 | |
|     private BehaviourFilter behaviourFilter;
 | |
|     private DictionaryDAO dictionaryDAO;
 | |
| 
 | |
|     private HiddenAspect hiddenAspect;
 | |
| 
 | |
|     private StoreRef storeRef;
 | |
|     private String rootPath;
 | |
|     private Map<String, List<String>> kindToRenditionNames;
 | |
|     private Set<String> ignoreChildren = Collections.emptySet();
 | |
|     private Set<QName> ignoreChildrenQNames = Collections.emptySet();
 | |
|     
 | |
|     // note: cache is tenant-aware (if using TransctionalCache impl)
 | |
|     
 | |
|     private SimpleCache<String, Object> singletonCache; // eg. for cmisRootNodeRef, cmisRenditionMapping
 | |
|     private final String KEY_CMIS_ROOT_NODEREF = "key.cmisRoot.noderef";
 | |
|     private final String KEY_CMIS_RENDITION_MAPPING_NODEREF = "key.cmisRenditionMapping.noderef";
 | |
|     
 | |
|     private String proxyUser;
 | |
|     private boolean openHttpSession = false;
 | |
| 
 | |
|     // OpenCMIS objects
 | |
|     private BigInteger typesDefaultMaxItems = TYPES_DEFAULT_MAX_ITEMS;
 | |
|     private BigInteger typesDefaultDepth = TYPES_DEFAULT_DEPTH;
 | |
|     private BigInteger objectsDefaultMaxItems = OBJECTS_DEFAULT_MAX_ITEMS;
 | |
|     private BigInteger objectsDefaultDepth = OBJECTS_DEFAULT_DEPTH;
 | |
| 
 | |
|     private List<PermissionDefinition> repositoryPermissions;
 | |
|     private Map<String, PermissionMapping> permissionMappings;
 | |
| 
 | |
|     private ObjectFilter objectFilter;
 | |
| 
 | |
|     // Bulk update properties 
 | |
|     private int bulkMaxItems = 1000;
 | |
|     private int bulkBatchSize = 20;
 | |
|     private int bulkWorkerThreads = 2;
 | |
|     
 | |
|     // --------------------------------------------------------------
 | |
|     // Configuration
 | |
|     // --------------------------------------------------------------
 | |
| 
 | |
|     public void setObjectFilter(ObjectFilter objectFilter)
 | |
|     {
 | |
| 		this.objectFilter = objectFilter;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
|      * Sets the root store.
 | |
|      * 
 | |
|      * @param store
 | |
|      *            store_type://store_id
 | |
|      */
 | |
|     public void setStore(String store)
 | |
|     {
 | |
|         this.storeRef = new StoreRef(store);
 | |
|     }
 | |
| 
 | |
|     public void setSiteService(SiteService siteService)
 | |
|     {
 | |
| 		this.siteService = siteService;
 | |
| 	}
 | |
| 
 | |
| 	public void setActivityPoster(CmisActivityPoster activityPoster)
 | |
|     {
 | |
| 		this.activityPoster = activityPoster;
 | |
| 	}
 | |
|     
 | |
| 	public CmisActivityPoster getActivityPoster()
 | |
| 	{
 | |
| 		return activityPoster;
 | |
| 	}
 | |
| 
 | |
| 	public void setHiddenAspect(HiddenAspect hiddenAspect)
 | |
|     {
 | |
| 		this.hiddenAspect = hiddenAspect;
 | |
| 	}
 | |
| 
 | |
|     public boolean isHidden(NodeRef nodeRef)
 | |
|     {
 | |
|         final FileFilterMode.Client client = FileFilterMode.getClient();
 | |
|     	return (hiddenAspect.getVisibility(client, nodeRef) == Visibility.NotVisible);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets the root path.
 | |
|      * 
 | |
|      * @param path
 | |
|      *            path within default store
 | |
|      */
 | |
|     public void setRootPath(String path)
 | |
|     {
 | |
|         rootPath = path;
 | |
|     }
 | |
| 
 | |
|     public BigInteger getTypesDefaultMaxItems()
 | |
|     {
 | |
|         return typesDefaultMaxItems;
 | |
|     }
 | |
| 
 | |
|     public void setTypesDefaultMaxItems(BigInteger typesDefaultMaxItems)
 | |
|     {
 | |
|         this.typesDefaultMaxItems = typesDefaultMaxItems;
 | |
|     }
 | |
| 
 | |
|     public BigInteger getTypesDefaultDepth()
 | |
|     {
 | |
|         return typesDefaultDepth;
 | |
|     }
 | |
| 
 | |
|     public void setTypesDefaultDepth(BigInteger typesDefaultDepth)
 | |
|     {
 | |
|         this.typesDefaultDepth = typesDefaultDepth;
 | |
|     }
 | |
| 
 | |
|     public BigInteger getObjectsDefaultMaxItems()
 | |
|     {
 | |
|         return objectsDefaultMaxItems;
 | |
|     }
 | |
| 
 | |
|     public void setObjectsDefaultMaxItems(BigInteger objectsDefaultMaxItems)
 | |
|     {
 | |
|         this.objectsDefaultMaxItems = objectsDefaultMaxItems;
 | |
|     }
 | |
| 
 | |
|     public BigInteger getObjectsDefaultDepth()
 | |
|     {
 | |
|         return objectsDefaultDepth;
 | |
|     }
 | |
| 
 | |
|     public void setObjectsDefaultDepth(BigInteger objectsDefaultDepth)
 | |
|     {
 | |
|         this.objectsDefaultDepth = objectsDefaultDepth;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Set rendition kind mapping.
 | |
|      */
 | |
|     public void setRenditionKindMapping(Map<String, List<String>> renditionKinds)
 | |
|     {
 | |
|         this.kindToRenditionNames = renditionKinds;
 | |
|     }
 | |
| 
 | |
|     public void setIgnoreChildren(Set<String> ignoreChildren)
 | |
|     {
 | |
|         this.ignoreChildren = ignoreChildren;
 | |
|     }
 | |
| 
 | |
|     public void setOpenHttpSession(boolean openHttpSession)
 | |
|     {
 | |
|         this.openHttpSession = openHttpSession;
 | |
|     }
 | |
| 
 | |
|     public boolean openHttpSession()
 | |
|     {
 | |
|         return openHttpSession;
 | |
|     }
 | |
| 
 | |
|     public void setThumbnailService(ThumbnailService thumbnailService)
 | |
|     {
 | |
| 		this.thumbnailService = thumbnailService;
 | |
| 	}
 | |
|     
 | |
| 	public void setServiceRegistry(ServiceRegistry serviceRegistry)
 | |
| 	{
 | |
| 		this.serviceRegistry = serviceRegistry;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
|      * Sets the descriptor service.
 | |
|      */
 | |
|     public void setDescriptorService(DescriptorService descriptorService)
 | |
|     {
 | |
|         this.descriptorService = descriptorService;
 | |
|     }
 | |
| 
 | |
|     public DescriptorService getDescriptorService()
 | |
|     {
 | |
|         return descriptorService;
 | |
|     }
 | |
| 
 | |
|     public void setBehaviourFilter(BehaviourFilter behaviourFilter)
 | |
|     {
 | |
|         this.behaviourFilter = behaviourFilter;
 | |
|     }
 | |
| 
 | |
|     public void setDictionaryDAO(DictionaryDAO dictionaryDAO)
 | |
|     {
 | |
|         this.dictionaryDAO = dictionaryDAO;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets the node service.
 | |
|      */
 | |
|     public void setNodeService(NodeService nodeService)
 | |
|     {
 | |
|         this.nodeService = nodeService;
 | |
|     }
 | |
| 
 | |
|     public NodeService getNodeService()
 | |
|     {
 | |
|         return nodeService;
 | |
|     }
 | |
| 
 | |
| 	public void setActionService(ActionService actionService)
 | |
| 	{
 | |
| 		this.actionService = actionService;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
|      * Sets the version service.
 | |
|      */
 | |
|     public void setVersionService(VersionService versionService)
 | |
|     {
 | |
|         this.versionService = versionService;
 | |
|     }
 | |
| 
 | |
|     public VersionService getVersionService()
 | |
|     {
 | |
|         return versionService;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets the checkOut/checkIn service.
 | |
|      */
 | |
|     public void setCheckOutCheckInService(CheckOutCheckInService checkOutCheckInService)
 | |
|     {
 | |
|         this.checkOutCheckInService = checkOutCheckInService;
 | |
|     }
 | |
| 
 | |
|     public CheckOutCheckInService getCheckOutCheckInService()
 | |
|     {
 | |
|         return checkOutCheckInService;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets the lock service.
 | |
|      */
 | |
|     public LockService getLockService()
 | |
|     {
 | |
|         return lockService;
 | |
|     }
 | |
| 
 | |
|     public void setLockService(LockService lockService)
 | |
|     {
 | |
|         this.lockService = lockService;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets the content service.
 | |
|      */
 | |
|     public void setContentService(ContentService contentService)
 | |
|     {
 | |
|         this.contentService = contentService;
 | |
|     }
 | |
| 
 | |
|     public ContentService getContentService()
 | |
|     {
 | |
|         return contentService;
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Sets the event publisher
 | |
|      */
 | |
|     public void setEventPublisher(EventPublisher eventPublisher)
 | |
|     {
 | |
|         this.eventPublisher = eventPublisher;
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Sets the rendition service.
 | |
|      */
 | |
|     public void setrenditionService(RenditionService renditionService)
 | |
|     {
 | |
|         this.renditionService = renditionService;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets the file folder service.
 | |
|      */
 | |
|     public void setFileFolderService(FileFolderService fileFolderService)
 | |
|     {
 | |
|         this.fileFolderService = fileFolderService;
 | |
|     }
 | |
| 
 | |
|     public FileFolderService getFileFolderService()
 | |
|     {
 | |
|         return fileFolderService;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets the tenant admin service.
 | |
|      */
 | |
|     public void setTenantAdminService(TenantAdminService tenantAdminService)
 | |
|     {
 | |
|         this.tenantAdminService = tenantAdminService;
 | |
|     }
 | |
|     
 | |
|     public void setSingletonCache(SimpleCache<String, Object> singletonCache)
 | |
|     {
 | |
|         this.singletonCache = singletonCache;
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Sets the transaction service.
 | |
|      */
 | |
|     public void setTransactionService(TransactionService transactionService)
 | |
|     {
 | |
|         this.transactionService = transactionService;
 | |
|     }
 | |
| 
 | |
|     public TransactionService getTransactionService()
 | |
|     {
 | |
|         return transactionService;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets the authentication service.
 | |
|      */
 | |
|     public void setAuthenticationService(AuthenticationService authenticationService)
 | |
|     {
 | |
|         this.authenticationService = authenticationService;
 | |
|     }
 | |
| 
 | |
|     public AuthenticationService getAuthenticationService()
 | |
|     {
 | |
|         return authenticationService;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets the permission service.
 | |
|      */
 | |
|     public void setPermissionService(PermissionService permissionService)
 | |
|     {
 | |
|         this.permissionService = permissionService;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets the permission model DAO.
 | |
|      */
 | |
|     public void setPermissionModelDao(ModelDAO permissionModelDao)
 | |
|     {
 | |
|         this.permissionModelDao = permissionModelDao;
 | |
|     }
 | |
| 
 | |
|     public void setOpenCMISDictionaryService(CMISDictionaryService cmisDictionaryService)
 | |
|     {
 | |
|         this.cmisDictionaryService = cmisDictionaryService;
 | |
|     }
 | |
| 
 | |
|     public void setOpenCMISDictionaryService11(CMISDictionaryService cmisDictionaryService)
 | |
|     {
 | |
|         this.cmisDictionaryService11 = cmisDictionaryService;
 | |
|     }
 | |
| 
 | |
|     public CMISDictionaryService getOpenCMISDictionaryService()
 | |
|     {
 | |
|         CmisVersion cmisVersion = getRequestCmisVersion();
 | |
|         if(cmisVersion.equals(CmisVersion.CMIS_1_0))
 | |
|         {
 | |
|             return cmisDictionaryService;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return cmisDictionaryService11;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets the OpenCMIS query service.
 | |
|      */
 | |
|     public void setOpenCMISQueryService(CMISQueryService cmisQueryService)
 | |
|     {
 | |
|         this.cmisQueryService = cmisQueryService;
 | |
|     }
 | |
| 
 | |
|     public void setOpenCMISQueryService11(CMISQueryService cmisQueryService)
 | |
|     {
 | |
|         this.cmisQueryService11 = cmisQueryService;
 | |
|     }
 | |
|     
 | |
|     public CMISQueryService getOpenCMISQueryService()
 | |
|     {
 | |
|         CmisVersion cmisVersion = getRequestCmisVersion();
 | |
|         if(cmisVersion.equals(CmisVersion.CMIS_1_0))
 | |
|         {
 | |
|             return cmisQueryService;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return cmisQueryService11;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets the MIME type service.
 | |
|      */
 | |
|     public void setMimetypeService(MimetypeService mimetypeService)
 | |
|     {
 | |
|         this.mimetypeService = mimetypeService;
 | |
|     }
 | |
| 
 | |
|     public MimetypeService getMimetypeService()
 | |
|     {
 | |
|         return mimetypeService;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets the audit service.
 | |
|      */
 | |
|     public void setAuditService(AuditService auditService)
 | |
|     {
 | |
|         this.auditService = auditService;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets the namespace service.
 | |
|      */
 | |
|     public void setNamespaceService(NamespaceService namespaceService)
 | |
|     {
 | |
|         this.namespaceService = namespaceService;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets the search service.
 | |
|      */
 | |
|     public void setSearchService(SearchService searchService)
 | |
|     {
 | |
|         this.searchService = searchService;
 | |
|     }
 | |
| 
 | |
|     public SearchService getSearchService()
 | |
|     {
 | |
|         return searchService;
 | |
|     }
 | |
| 
 | |
|     public void setDictionaryService(DictionaryService dictionaryService)
 | |
|     {
 | |
|         this.dictionaryService = dictionaryService;
 | |
|     }
 | |
| 
 | |
|     public DictionaryService getDictionaryService()
 | |
|     {
 | |
|         return dictionaryService;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Not implemented
 | |
|      * @throws UnsupportedOperationException always
 | |
|      */
 | |
|     public void setProxyUser(String proxyUser)
 | |
|     {
 | |
| //        this.proxyUser = proxyUser;
 | |
|         throw new UnsupportedOperationException("proxyUser setting not implemented.  Please raise a JIRA request.");
 | |
|     }
 | |
| 
 | |
|     public String getProxyUser()
 | |
|     {
 | |
|         return proxyUser;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets bulk update properties.
 | |
|      */
 | |
|     public void setBulkMaxItems(int size)
 | |
|     {
 | |
|         bulkMaxItems = size;
 | |
|     }
 | |
|     
 | |
|     public int getBulkMaxItems()
 | |
|     {
 | |
|         return bulkMaxItems;
 | |
|     }
 | |
|     
 | |
|     public void setBulkBatchSize(int size)
 | |
|     {
 | |
|         bulkBatchSize = size;
 | |
|     }
 | |
|     
 | |
|     public int getBulkBatchSize()
 | |
|     {
 | |
|         return bulkBatchSize;
 | |
|     }
 | |
|     
 | |
|     public void setBulkWorkerThreads(int threads)
 | |
|     {
 | |
|         bulkWorkerThreads = threads;
 | |
|     }
 | |
|     
 | |
|     public int getBulkWorkerThreads()
 | |
|     {
 | |
|         return bulkWorkerThreads;
 | |
|     }
 | |
|     
 | |
|     // --------------------------------------------------------------
 | |
|     // Lifecycle methods
 | |
|     // --------------------------------------------------------------
 | |
| 
 | |
|     private File tmp;
 | |
|     
 | |
|     public void setup()
 | |
|     {
 | |
|     	File tempDir = TempFileProvider.getTempDir();
 | |
|     	this.tmp = new File(tempDir, "CMISAppend");
 | |
|     	if(!this.tmp.exists() && !this.tmp.mkdir())
 | |
|     	{
 | |
|     		throw new AlfrescoRuntimeException("Failed to create CMIS temporary directory");
 | |
|     	}
 | |
|         dictionaryDAO.registerListener(this);
 | |
|     }
 | |
|     
 | |
|     public void init()
 | |
|     {
 | |
|         // register as tenant deployer
 | |
|         tenantAdminService.register(this);
 | |
| 
 | |
|         // set up and cache rendition mapping
 | |
|         getRenditionMapping();
 | |
| 
 | |
|         // cache root node ref
 | |
|         getRootNodeRef();
 | |
| 
 | |
|         // cache permission definitions and permission mappings
 | |
|         repositoryPermissions = getRepositoryPermissions();
 | |
|         permissionMappings = getPermissionMappings();
 | |
|     }
 | |
| 
 | |
|     public void destroy()
 | |
|     {
 | |
|         singletonCache.remove(KEY_CMIS_ROOT_NODEREF);
 | |
|         singletonCache.remove(KEY_CMIS_RENDITION_MAPPING_NODEREF);
 | |
|     }
 | |
| 
 | |
|     public void onEnableTenant()
 | |
|     {
 | |
|         init();
 | |
|     }
 | |
| 
 | |
|     public void onDisableTenant()
 | |
|     {
 | |
|         destroy();
 | |
|     }
 | |
| 
 | |
|     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
 | |
|     {
 | |
|         lifecycle.setApplicationContext(applicationContext);
 | |
|     }
 | |
| 
 | |
|     public void onApplicationEvent(ApplicationContextEvent event)
 | |
|     {
 | |
|         lifecycle.onApplicationEvent(event);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Hooks into Spring Application Lifecycle.
 | |
|      */
 | |
|     private class ProcessorLifecycle extends AbstractLifecycleBean
 | |
|     {
 | |
|         @Override
 | |
|         protected void onBootstrap(ApplicationEvent event)
 | |
|         {
 | |
|             init();
 | |
|         }
 | |
| 
 | |
|         @Override
 | |
|         protected void onShutdown(ApplicationEvent event)
 | |
|         {
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // --------------------------------------------------------------
 | |
|     // Alfresco methods
 | |
|     // --------------------------------------------------------------
 | |
| 
 | |
|     /*
 | |
|      * For the given cmis property name get the corresponding Alfresco property name.
 | |
|      * 
 | |
|      * Certain CMIS properties (e.g. cmis:creationDate and cmis:lastModifiedBy) don't
 | |
|      * have direct mappings to Alfresco properties through the CMIS dictionary, because
 | |
|      * these mappings should not be exposed outside the repository through CMIS. For these,
 | |
|      * however, this method provides the mapping so that the sort works.
 | |
|      * 
 | |
|      */
 | |
|     public Pair<QName, Boolean> getSortProperty(String cmisPropertyName, String direction)
 | |
|     {
 | |
|     	QName sortPropName = null;
 | |
|     	Pair<QName, Boolean> sortProp = null;
 | |
| 
 | |
|         PropertyDefinitionWrapper propDef = getOpenCMISDictionaryService().findPropertyByQueryName(cmisPropertyName);
 | |
|         if (propDef != null)
 | |
|         {
 | |
| 	        if (propDef.getPropertyId().equals(PropertyIds.BASE_TYPE_ID))
 | |
| 	        {
 | |
| 	            // special-case (see also ALF-13968) - for getChildren, using "cmis:baseTypeId" allows sorting of folders first and vice-versa (cmis:folder <-> cmis:document)
 | |
| 	        	sortPropName = GetChildrenCannedQuery.SORT_QNAME_NODE_IS_FOLDER;
 | |
| 	        }
 | |
| 	        else
 | |
| 	        {
 | |
| 	        	sortPropName = propDef.getPropertyAccessor().getMappedProperty();
 | |
| 	        }
 | |
| 
 | |
| 	        if (sortPropName == null)
 | |
| 	        {
 | |
| 	        	// ok to map these properties because we are always getting current versions of nodes
 | |
| 	        	sortPropName = SORT_PROPERTY_MAPPINGS.get(cmisPropertyName);
 | |
| 	        }
 | |
| 	    }
 | |
| 
 | |
|     	if (sortPropName != null)
 | |
|     	{
 | |
|     		boolean sortAsc = (direction == null ? true : direction.equalsIgnoreCase("asc"));
 | |
|     		sortProp = new Pair<QName, Boolean>(sortPropName, sortAsc);
 | |
|     	}
 | |
|     	else
 | |
|     	{
 | |
|     		if (logger.isDebugEnabled())
 | |
|     		{
 | |
|     			logger.debug("Ignore sort property '" + cmisPropertyName + " - mapping not found");
 | |
|     		}
 | |
|     	}
 | |
| 
 | |
|         return sortProp;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Asynchronously generates thumbnails for the given node.
 | |
|      *  
 | |
|      * @param nodeRef NodeRef
 | |
|      * @param thumbnailNames Set<String>
 | |
|      */
 | |
|     public void createThumbnails(NodeRef nodeRef, Set<String> thumbnailNames)
 | |
|     {
 | |
|     	if(thumbnailNames == null || thumbnailNames.size() == 0)
 | |
|     	{
 | |
|     		return;
 | |
|     	}
 | |
| 
 | |
|         ThumbnailRegistry registry = thumbnailService.getThumbnailRegistry();
 | |
| 
 | |
|         // If there's nothing currently registered to generate thumbnails for the
 | |
|         //  specified mimetype, then log a message and bail out
 | |
|         Serializable value = this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
 | |
|         ContentData contentData = DefaultTypeConverter.INSTANCE.convert(ContentData.class, value);
 | |
|         if (contentData == null)
 | |
|         {
 | |
|         	logger.info("Unable to create thumbnails as there is no content");
 | |
|         	return;
 | |
|         }
 | |
| 
 | |
|     	long size = contentData.getSize();
 | |
|     	String mimeType = contentData.getMimetype();
 | |
| 
 | |
|     	for(String thumbnailName : thumbnailNames)
 | |
|     	{
 | |
| 	        // Use the thumbnail registy to get the details of the thumbail
 | |
| 	        ThumbnailDefinition details = registry.getThumbnailDefinition(thumbnailName);
 | |
| 	        if(details == null)
 | |
| 	        {
 | |
| 	            // Throw exception 
 | |
| 	            logger.warn("The thumbnail name '" + thumbnailName + "' is not registered");
 | |
| 	            continue;
 | |
| 	        }
 | |
| 	        else
 | |
| 	        {
 | |
| 		        if(registry.isThumbnailDefinitionAvailable(contentData.getContentUrl(), mimeType, size, nodeRef, details))
 | |
| 		        {
 | |
| 		            org.alfresco.service.cmr.action.Action action = ThumbnailHelper.createCreateThumbnailAction(details, serviceRegistry);
 | |
| 		            
 | |
| 		            // Queue async creation of thumbnail
 | |
| 		            actionService.executeAction(action, nodeRef, true, true);
 | |
| 		        }
 | |
| 		        else
 | |
| 		        {
 | |
| 		        	logger.info("Unable to create thumbnail '" + details.getName() + "' for " +
 | |
| 		        			mimeType + " as no transformer is currently available");
 | |
| 		        }
 | |
| 	        }
 | |
|     	}
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Extracts metadata for the node.
 | |
|      *  
 | |
|      * @param nodeRef NodeRef
 | |
|      */
 | |
|     public void extractMetadata(NodeRef nodeRef)
 | |
|     {
 | |
|     	org.alfresco.service.cmr.action.Action action = actionService.createAction(ContentMetadataExtracter.EXECUTOR_NAME);
 | |
|     	actionService.executeAction(action, nodeRef, true, false);
 | |
|     }
 | |
| 
 | |
|     public SiteInfo getSite(NodeRef nodeRef)
 | |
|     {
 | |
|     	return siteService.getSite(nodeRef);
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      *  Should the node be filtered?
 | |
|      */
 | |
| 	public boolean filter(NodeRef nodeRef)
 | |
|     {
 | |
|     	return objectFilter.filter(nodeRef);
 | |
|     }
 | |
| 
 | |
|     public boolean disableBehaviour(QName className)
 | |
|     {
 | |
|         boolean wasEnabled = behaviourFilter.isEnabled(className);
 | |
|         if(wasEnabled)
 | |
|         {
 | |
|         	behaviourFilter.disableBehaviour(className);
 | |
|         }
 | |
|         return wasEnabled;
 | |
|     }
 | |
| 	
 | |
|     public boolean enableBehaviour(QName className)
 | |
|     {
 | |
|         boolean isEnabled = behaviourFilter.isEnabled(className);
 | |
|         if(!isEnabled)
 | |
|         {
 | |
|             behaviourFilter.enableBehaviour(className);
 | |
|         }
 | |
|         return isEnabled;
 | |
|     }
 | |
| 
 | |
|     
 | |
|     public boolean disableBehaviour(QName className, NodeRef nodeRef)
 | |
|     {
 | |
|         boolean wasEnabled = behaviourFilter.isEnabled(nodeRef, className);
 | |
|         if(wasEnabled)
 | |
|         {
 | |
|             behaviourFilter.disableBehaviour(nodeRef, className);
 | |
|         }
 | |
|         return wasEnabled;
 | |
|     }
 | |
|     
 | |
|     public boolean enableBehaviour(QName className, NodeRef nodeRef)
 | |
|     {
 | |
|         boolean isEnabled = behaviourFilter.isEnabled(nodeRef, className);
 | |
|         if(!isEnabled)
 | |
|         {
 | |
|             behaviourFilter.enableBehaviour(nodeRef, className);
 | |
|         }
 | |
|         return isEnabled;
 | |
|     }
 | |
| 
 | |
|     public StoreRef getRootStoreRef()
 | |
|     {
 | |
|         return getRootNodeRef().getStoreRef();
 | |
|     }
 | |
| 
 | |
|     public void deleteNode(NodeRef nodeRef, boolean postActivity)
 | |
|     {
 | |
|         ActivityInfo activityInfo = null;
 | |
| 
 | |
|         // post activity after removal of the node
 | |
|         postActivity &= !hiddenAspect.hasHiddenAspect(nodeRef);
 | |
|     	if(postActivity)
 | |
|     	{
 | |
|         	// get this information before the node is deleted
 | |
| 	    	activityInfo = activityPoster.getActivityInfo(nodeRef);
 | |
|     	}
 | |
| 
 | |
|         getNodeService().deleteNode(nodeRef);
 | |
| 
 | |
|         // post activity after removal of the node
 | |
|         if(postActivity && activityInfo != null)
 | |
|         {
 | |
|         	activityPoster.postFileFolderDeleted(activityInfo);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     public RetryingTransactionHelper getRetryingTransactionHelper()
 | |
|     {
 | |
|     	return transactionService.getRetryingTransactionHelper();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns the root folder node ref.
 | |
|      */
 | |
|     public NodeRef getRootNodeRef()
 | |
|     {
 | |
|         NodeRef rootNodeRef = (NodeRef)singletonCache.get(KEY_CMIS_ROOT_NODEREF);
 | |
|         if (rootNodeRef == null)
 | |
|         {
 | |
|             rootNodeRef = AuthenticationUtil.runAs(new RunAsWork<NodeRef>()
 | |
|             {
 | |
|                 public NodeRef doWork() throws Exception
 | |
|                 {
 | |
|                     return transactionService.getRetryingTransactionHelper().doInTransaction(
 | |
|                             new RetryingTransactionCallback<NodeRef>()
 | |
|                             {
 | |
|                                 public NodeRef execute() throws Exception
 | |
|                                 {
 | |
|                                     NodeRef root = nodeService.getRootNode(storeRef);
 | |
|                                     List<NodeRef> rootNodes = searchService.selectNodes(root, rootPath, null,
 | |
|                                             namespaceService, false);
 | |
|                                     if (rootNodes.size() != 1)
 | |
|                                     {
 | |
|                                         throw new CmisRuntimeException("Unable to locate CMIS root path " + rootPath);
 | |
|                                     }
 | |
|                                     return rootNodes.get(0);
 | |
|                                 };
 | |
|                             }, true);
 | |
|                 }
 | |
|             }, AuthenticationUtil.getSystemUserName());
 | |
| 
 | |
|             if (rootNodeRef == null)
 | |
|             {
 | |
|                 throw new CmisObjectNotFoundException("Root folder path '" + rootPath + "' not found!");
 | |
|             }
 | |
| 
 | |
|             singletonCache.put(KEY_CMIS_ROOT_NODEREF, rootNodeRef);
 | |
|         }
 | |
| 
 | |
|         return rootNodeRef;
 | |
|     }
 | |
| 
 | |
|     public String getName(NodeRef nodeRef)
 | |
|     {
 | |
|         try
 | |
|         {
 | |
|             Object name = nodeService.getProperty(nodeRef, ContentModel.PROP_NAME);
 | |
|             return (name instanceof String ? (String) name : null);
 | |
|         }
 | |
|         catch(InvalidNodeRefException inre)
 | |
|         {
 | |
|             return null;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Cuts of the version information from an object id.
 | |
|      */
 | |
|     public String getCurrentVersionId(String objectId)
 | |
|     {
 | |
|         if (objectId == null)
 | |
|         {
 | |
|             return null;
 | |
|         }
 | |
| 
 | |
|         int sepIndex = objectId.lastIndexOf(ID_SEPERATOR);
 | |
|         if (sepIndex > -1)
 | |
|         {
 | |
|             return objectId.substring(0, sepIndex);
 | |
|         }
 | |
| 
 | |
|         return objectId;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Creates an object info object.
 | |
|      */
 | |
|     public CMISNodeInfoImpl createNodeInfo(String objectId)
 | |
|     {
 | |
|         return new CMISNodeInfoImpl(this, objectId);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Creates an object info object.
 | |
|      */
 | |
|     public CMISNodeInfoImpl createNodeInfo(NodeRef nodeRef)
 | |
|     {
 | |
|         return createNodeInfo(nodeRef, null);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Creates an object info object.
 | |
|      */
 | |
|     public CMISNodeInfoImpl createNodeInfo(NodeRef nodeRef, VersionHistory versionHistory)
 | |
|     {
 | |
|         return new CMISNodeInfoImpl(this, nodeRef, versionHistory);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Creates an object info object.
 | |
|      */
 | |
|     public CMISNodeInfoImpl createNodeInfo(AssociationRef assocRef)
 | |
|     {
 | |
|         return new CMISNodeInfoImpl(this, assocRef);
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|      * Strip store ref from the id, if there is one.
 | |
|      */
 | |
|     private String getGuid(String id)
 | |
|     {
 | |
|     	int idx = id.lastIndexOf("/");
 | |
|     	if(idx != -1)
 | |
|     	{
 | |
|     		return id.substring(idx + 1);
 | |
|     	}
 | |
|     	else
 | |
|     	{
 | |
|     		return id;
 | |
|     	}
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Construct an object id based on the incoming assocRef and versionLabel. The object id will always
 | |
|      * be the assocRef guid.
 | |
|      */
 | |
|     public String constructObjectId(AssociationRef assocRef, String versionLabel)
 | |
|     {
 | |
|         return constructObjectId(assocRef, versionLabel, isPublicApi());
 | |
|     }
 | |
|     
 | |
|     public String constructObjectId(AssociationRef assocRef, String versionLabel, boolean dropStoreRef)
 | |
|     {
 | |
|     	StringBuilder sb = new StringBuilder(CMISConnector.ASSOC_ID_PREFIX);
 | |
|     	if(dropStoreRef)
 | |
|     	{
 | |
|     		// always return the guid
 | |
|     		sb.append(assocRef.getId());
 | |
|     	}
 | |
|     	else
 | |
|     	{
 | |
|     		sb.append(assocRef.toString());
 | |
|     	}
 | |
| 
 | |
|     	if(versionLabel != null)
 | |
|     	{
 | |
|     		sb.append(CMISConnector.ID_SEPERATOR);
 | |
|     		sb.append(versionLabel);
 | |
|     	}
 | |
|     	return sb.toString();
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Construct an object id based on the incoming incomingObjectId. The object id will always
 | |
|      * be the node guid.
 | |
|      */
 | |
|     public String constructObjectId(String incomingObjectId)
 | |
|     {
 | |
|     	return constructObjectId(incomingObjectId, null);
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|      * Construct an object id based on the incoming incomingNodeId and versionLabel. The object id will always
 | |
|      * be the node guid.
 | |
|      */
 | |
|     public String constructObjectId(String incomingNodeId, String versionLabel)
 | |
|     {
 | |
|         return constructObjectId(incomingNodeId, versionLabel, isPublicApi());
 | |
|     }
 | |
|     
 | |
|     public String constructObjectId(String incomingNodeId, String versionLabel, boolean dropStoreRef)
 | |
|     {
 | |
|     	StringBuilder sb = new StringBuilder();
 | |
|     	if(dropStoreRef)
 | |
|     	{
 | |
|     		// always return the guid
 | |
|     		sb.append(getGuid(incomingNodeId));
 | |
|     	}
 | |
|     	else
 | |
|     	{
 | |
|     	    sb.append(incomingNodeId);
 | |
|     	}
 | |
|     	if(versionLabel != null)
 | |
|     	{
 | |
|     		sb.append(CMISConnector.ID_SEPERATOR);
 | |
|     		sb.append(versionLabel);
 | |
|     	}
 | |
|     	return sb.toString();
 | |
|     }
 | |
| 
 | |
|     public void createVersion(NodeRef nodeRef, VersionType versionType, String reason)
 | |
|     {
 | |
|     	if(versionService.getVersionHistory(nodeRef) == null)
 | |
|     	{
 | |
|     		// no version history. Make sure we have an initial major version 1.0.
 | |
|             Map<String, Serializable> versionProperties = new HashMap<String, Serializable>(2);
 | |
|             versionProperties.put(VersionModel.PROP_VERSION_TYPE, VersionType.MAJOR);
 | |
|             versionProperties.put(VersionModel.PROP_DESCRIPTION, "Initial version");
 | |
|             versionService.createVersion(nodeRef, versionProperties);
 | |
|     	}
 | |
| 
 | |
|         Map<String, Serializable> versionProperties = new HashMap<String, Serializable>(2);
 | |
|         versionProperties.put(VersionModel.PROP_VERSION_TYPE, versionType);
 | |
|         versionProperties.put(VersionModel.PROP_DESCRIPTION, reason);
 | |
|         versionService.createVersion(nodeRef, versionProperties);
 | |
|     }
 | |
| 
 | |
|     public CmisVersion getRequestCmisVersion()
 | |
|     {
 | |
|         CallContext callContext = AlfrescoCmisServiceCall.get();
 | |
|         CmisVersion cmisVersion = (callContext != null ? callContext.getCmisVersion() : CmisVersion.CMIS_1_0);
 | |
|         return cmisVersion;
 | |
|     }
 | |
| 
 | |
|     private boolean isPublicApi()
 | |
|     {
 | |
|     	boolean isPublicApi = false;
 | |
|     	CallContext callContext = AlfrescoCmisServiceCall.get();
 | |
|     	if(callContext != null)
 | |
|     	{
 | |
| 	    	String value = (String)callContext.get("isPublicApi");
 | |
| 	    	isPublicApi = (value == null ? false : Boolean.parseBoolean(value));
 | |
|     	}
 | |
|     	return isPublicApi;
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|      * Construct an object id based on the incoming incomingNodeRef and versionLabel. The object id will always
 | |
|      * be the incomingNodeRef guid.
 | |
|      */
 | |
|     public String constructObjectId(NodeRef incomingNodeRef, String versionLabel)
 | |
|     {
 | |
|         return constructObjectId(incomingNodeRef, versionLabel, isPublicApi());
 | |
|     }
 | |
|     
 | |
|     public String constructObjectId(NodeRef incomingNodeRef, String versionLabel, boolean dropStoreRef)
 | |
|     {
 | |
|     	StringBuilder sb = new StringBuilder();
 | |
|     	sb.append(dropStoreRef ? incomingNodeRef.getId() : incomingNodeRef.toString());
 | |
|     	if(versionLabel != null)
 | |
|     	{
 | |
|     		sb.append(CMISConnector.ID_SEPERATOR);
 | |
|     		sb.append(versionLabel);
 | |
|     	}
 | |
|     	return sb.toString();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Compiles a CMIS object if for a live node.
 | |
|      */
 | |
|     public String createObjectId(NodeRef nodeRef)
 | |
|     {
 | |
|         return createObjectId(nodeRef, isPublicApi());
 | |
|     }
 | |
|     
 | |
|     public String createObjectId(NodeRef nodeRef, boolean dropStoreRef)
 | |
|     {
 | |
|     	QName typeQName = nodeService.getType(nodeRef);
 | |
|         TypeDefinitionWrapper type = getOpenCMISDictionaryService().findNodeType(typeQName);
 | |
|     
 | |
|     	if(type instanceof ItemTypeDefinitionWrapper)
 | |
|     	{
 | |
|     		return constructObjectId(nodeRef, null);
 | |
|     	}
 | |
|     	
 | |
|         if(type instanceof FolderTypeDefintionWrapper)
 | |
|         {
 | |
|             return constructObjectId(nodeRef, null, dropStoreRef);
 | |
|         }
 | |
|         
 | |
|         Serializable versionLabel = getNodeService()
 | |
|                 .getProperty(nodeRef, ContentModel.PROP_VERSION_LABEL);
 | |
|         if (versionLabel == null)
 | |
|         {
 | |
|         	versionLabel = CMISConnector.UNVERSIONED_VERSION_LABEL;
 | |
|         }
 | |
| 
 | |
|         return constructObjectId(nodeRef, (String)versionLabel, dropStoreRef);
 | |
|     }
 | |
|     
 | |
|     private boolean isFolder(NodeRef nodeRef)
 | |
|     {
 | |
|         return getType(nodeRef) instanceof FolderTypeDefintionWrapper;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns the type definition of a node or <code>null</code> if no type
 | |
|      * definition could be found.
 | |
|      */
 | |
|     public TypeDefinitionWrapper getType(NodeRef nodeRef)
 | |
|     {
 | |
|         try
 | |
|         {
 | |
|             QName typeQName = nodeService.getType(nodeRef);
 | |
|             return getType(typeQName);
 | |
|         }
 | |
|         catch(InvalidNodeRefException inre)
 | |
|         {
 | |
|             return null;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     private TypeDefinitionWrapper getType(QName typeQName)
 | |
|     {
 | |
|         return getOpenCMISDictionaryService().findNodeType(typeQName);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns the type definition of an association or <code>null</code> if no
 | |
|      * type definition could be found.
 | |
|      */
 | |
|     public TypeDefinitionWrapper getType(AssociationRef assocRef)
 | |
|     {
 | |
|         QName typeQName = assocRef.getTypeQName();
 | |
|         return getOpenCMISDictionaryService().findAssocType(typeQName);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns the type definition of a node or <code>null</code> if no type
 | |
|      * definition could be found.
 | |
|      */
 | |
|     public TypeDefinitionWrapper getType(String cmisTypeId)
 | |
|     {
 | |
|         return getOpenCMISDictionaryService().findType(cmisTypeId);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns the definition after it has checked if the type can be used for
 | |
|      * object creation.
 | |
|      */
 | |
|     public TypeDefinitionWrapper getTypeForCreate(String cmisTypeId, BaseTypeId baseTypeId)
 | |
|     {
 | |
|         TypeDefinitionWrapper type = getType(cmisTypeId);
 | |
|         if ((type == null) || (type.getBaseTypeId() != baseTypeId))
 | |
|         {
 | |
|             switch (baseTypeId)
 | |
|             {
 | |
|             case CMIS_DOCUMENT:
 | |
|                 throw new CmisConstraintException("Type is not a document type!");
 | |
|             case CMIS_FOLDER:
 | |
|                 throw new CmisConstraintException("Type is not a folder type!");
 | |
|             case CMIS_RELATIONSHIP:
 | |
|                 throw new CmisConstraintException("Type is not a relationship type!");
 | |
|             case CMIS_POLICY:
 | |
|                 throw new CmisConstraintException("Type is not a policy type!");
 | |
|             case CMIS_ITEM:
 | |
|                 throw new CmisConstraintException("Type is not an item type!");    
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if (!type.getTypeDefinition(false).isCreatable())
 | |
|         {
 | |
|             throw new CmisConstraintException("Type is not creatable!");
 | |
|         }
 | |
| 
 | |
|         return type;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Applies a versioning state to a document.
 | |
|      */
 | |
|     public void applyVersioningState(NodeRef nodeRef, VersioningState versioningState)
 | |
|     {
 | |
|         if (versioningState == VersioningState.CHECKEDOUT)
 | |
|         {
 | |
|             if (!nodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE))
 | |
|             {
 | |
|                 nodeService.addAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE, null);
 | |
|             }
 | |
| 
 | |
|             Map<String, Serializable> versionProperties = new HashMap<String, Serializable>(5);
 | |
|             versionProperties.put(VersionModel.PROP_VERSION_TYPE, VersionType.MAJOR);
 | |
|             versionProperties.put(VersionModel.PROP_DESCRIPTION, "Initial Version");
 | |
| 
 | |
|             getCheckOutCheckInService().checkout(nodeRef);
 | |
|         }
 | |
|         else if ((versioningState == VersioningState.MAJOR) || (versioningState == VersioningState.MINOR))
 | |
|         {
 | |
|             if (!nodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE))
 | |
|             {
 | |
|                 nodeService.addAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE, null);
 | |
|             }
 | |
| 
 | |
|             Map<String, Serializable> versionProperties = new HashMap<String, Serializable>(5);
 | |
|             versionProperties.put(
 | |
|                     VersionModel.PROP_VERSION_TYPE,
 | |
|                     versioningState == VersioningState.MAJOR ? VersionType.MAJOR : VersionType.MINOR);
 | |
|             versionProperties.put(VersionModel.PROP_DESCRIPTION, "Initial Version");
 | |
| 
 | |
|             versionService.createVersion(nodeRef, versionProperties);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Checks if a child of a given type can be added to a given folder.
 | |
|      */
 | |
|     @SuppressWarnings("unchecked")
 | |
|     public void checkChildObjectType(CMISNodeInfo folderInfo, String childType)
 | |
|     {
 | |
|         TypeDefinitionWrapper targetType = folderInfo.getType();
 | |
|         PropertyDefinitionWrapper allowableChildObjectTypeProperty = targetType
 | |
|                 .getPropertyById(PropertyIds.ALLOWED_CHILD_OBJECT_TYPE_IDS);
 | |
|         List<String> childTypes = (List<String>) allowableChildObjectTypeProperty.getPropertyAccessor().getValue(
 | |
|                 folderInfo);
 | |
| 
 | |
|         if ((childTypes == null) || childTypes.isEmpty())
 | |
|         {
 | |
|             return;
 | |
|         }
 | |
|         
 | |
|         if (!childTypes.contains(childType))
 | |
|         {
 | |
|             throw new CmisConstraintException("Objects of type '" + childType + "' cannot be added to this folder!");
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Creates the CMIS object for a node.
 | |
|      */
 | |
|     public ObjectData createCMISObject(CMISNodeInfo info, FileInfo node, String filter,
 | |
|             boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter,
 | |
|             boolean includePolicyIds, boolean includeAcl)
 | |
|     {
 | |
|         if (info.getType() == null)
 | |
|         {
 | |
|             throw new CmisObjectNotFoundException("No corresponding type found! Not a CMIS object?");
 | |
|         }
 | |
| 
 | |
|         Properties nodeProps = getNodeProperties(info, node, filter, info.getType());
 | |
| 
 | |
|         return createCMISObjectImpl(info, nodeProps, filter, includeAllowableActions, includeRelationships,
 | |
|                 renditionFilter, includePolicyIds, includeAcl);
 | |
|     }
 | |
| 
 | |
|     public ObjectData createCMISObject(CMISNodeInfo info, String filter, boolean includeAllowableActions,
 | |
|             IncludeRelationships includeRelationships, String renditionFilter, boolean includePolicyIds,
 | |
|             boolean includeAcl)
 | |
|     {
 | |
|         if (info.getType() == null)
 | |
|         {
 | |
|             throw new CmisObjectNotFoundException("No corresponding type found! Not a CMIS object?");
 | |
|         }
 | |
| 
 | |
|         Properties nodeProps = (info.isRelationship() ? getAssocProperties(info, filter) : getNodeProperties(info,
 | |
|                 filter));
 | |
| 
 | |
|         return createCMISObjectImpl(info, nodeProps, filter, includeAllowableActions, includeRelationships,
 | |
|                 renditionFilter, includePolicyIds, includeAcl);
 | |
|     }
 | |
| 
 | |
|     @SuppressWarnings("unchecked")
 | |
|     private ObjectData createCMISObjectImpl(final CMISNodeInfo info, Properties nodeProps, String filter,
 | |
|             boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter,
 | |
|             boolean includePolicyIds, boolean includeAcl)
 | |
|     {
 | |
|         final ObjectDataImpl result = new ObjectDataImpl();
 | |
| 
 | |
|         // set allowable actions
 | |
|         if (includeAllowableActions)
 | |
|         {
 | |
|             result.setAllowableActions(getAllowableActions(info));
 | |
|         }
 | |
| 
 | |
|         // set policy ids
 | |
|         if (includePolicyIds)
 | |
|         {
 | |
|             result.setPolicyIds(new PolicyIdListImpl());
 | |
|         }
 | |
| 
 | |
|         if (info.isRelationship())
 | |
|         {
 | |
|             // set properties
 | |
|             result.setProperties(getAssocProperties(info, filter));
 | |
| 
 | |
|             // set ACL
 | |
|             if (includeAcl)
 | |
|             {
 | |
|                 // association have no ACL - return an empty list of ACEs
 | |
|                 result.setAcl(new AccessControlListImpl((List<Ace>) Collections.EMPTY_LIST));
 | |
|                 result.setIsExactAcl(Boolean.FALSE);
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             // set properties
 | |
|             result.setProperties(nodeProps);
 | |
| 
 | |
|             // set relationships
 | |
|             if (includeRelationships != IncludeRelationships.NONE)
 | |
|             {
 | |
|                 result.setRelationships(getRelationships(info.getNodeRef(), includeRelationships));
 | |
|             }
 | |
| 
 | |
|             // set renditions
 | |
|             if (!RENDITION_NONE.equals(renditionFilter))
 | |
|             {
 | |
|                 List<RenditionData> renditions = getRenditions(info.getNodeRef(), renditionFilter, null, null);
 | |
|                 if ((renditions != null) && (!renditions.isEmpty()))
 | |
|                 {
 | |
|                     result.setRenditions(renditions);
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                 	result.setRenditions(Collections.EMPTY_LIST);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             // set ACL
 | |
|             if (includeAcl)
 | |
|             {
 | |
|             	AuthenticationUtil.runAsSystem(new RunAsWork<Void>()
 | |
|             	{
 | |
| 					@Override
 | |
| 					public Void doWork() throws Exception
 | |
| 					{
 | |
| 					    Acl acl = getACL(info.getCurrentNodeNodeRef(), false);
 | |
| 		                if (acl != null)
 | |
| 		                {
 | |
| 					        result.setAcl(acl);
 | |
| 					        result.setIsExactAcl(acl.isExact());
 | |
| 		                }
 | |
| 						return null;
 | |
| 					}
 | |
|             	});
 | |
|             }
 | |
| 
 | |
|             // add aspects
 | |
|             List<CmisExtensionElement> extensions = getAspectExtensions(info, filter, result.getProperties()
 | |
|                     .getProperties().keySet());
 | |
|             if (!extensions.isEmpty())
 | |
|             {
 | |
|                 result.getProperties().setExtensions(
 | |
|                         Collections.singletonList((CmisExtensionElement) new CmisExtensionElementImpl(
 | |
|                                 ALFRESCO_EXTENSION_NAMESPACE, ASPECTS, null, extensions)));
 | |
|             }
 | |
|         }
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     public String getPath(NodeRef nodeRef)
 | |
|     {
 | |
|         try
 | |
|         {
 | |
|             Path path = nodeService.getPath(nodeRef);
 | |
| 
 | |
|             // skip to CMIS root path
 | |
|             NodeRef rootNode = getRootNodeRef();
 | |
|             int i = 0;
 | |
|             while (i < path.size())
 | |
|             {
 | |
|                 Path.Element element = path.get(i);
 | |
|                 if (element instanceof ChildAssocElement)
 | |
|                 {
 | |
|                     ChildAssociationRef assocRef = ((ChildAssocElement) element).getRef();
 | |
|                     NodeRef node = assocRef.getChildRef();
 | |
|                     if (node.equals(rootNode))
 | |
|                     {
 | |
|                         break;
 | |
|                     }
 | |
|                 }
 | |
|                 i++;
 | |
|             }
 | |
| 
 | |
|             StringBuilder displayPath = new StringBuilder(64);
 | |
| 
 | |
|             if (path.size() - i == 1)
 | |
|             {
 | |
|                 // render root path
 | |
|                 displayPath.append("/");
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 // render CMIS scoped path
 | |
|                 i++;
 | |
|                 while (i < path.size())
 | |
|                 {
 | |
|                     Path.Element element = path.get(i);
 | |
|                     if (element instanceof ChildAssocElement)
 | |
|                     {
 | |
|                         ChildAssociationRef assocRef = ((ChildAssocElement) element).getRef();
 | |
|                         NodeRef node = assocRef.getChildRef();
 | |
|                         displayPath.append("/");
 | |
|                         displayPath.append(nodeService.getProperty(node, ContentModel.PROP_NAME));
 | |
|                     }
 | |
|                     i++;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return displayPath.toString();
 | |
|         }
 | |
|         catch(InvalidNodeRefException inre)
 | |
|         {
 | |
|             return null;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Gets the content from the repository.
 | |
|      */
 | |
|     public ContentStream getContentStream(CMISNodeInfo info, String streamId, BigInteger offset, BigInteger length)
 | |
|     {
 | |
|         // get the type and check if the object can have content
 | |
|         TypeDefinitionWrapper type = info.getType();
 | |
|         checkDocumentTypeForContent(type);
 | |
| 
 | |
|         // looks like a document, now get the content
 | |
|         ContentStreamImpl result = new ContentStreamImpl();
 | |
|         result.setFileName(info.getName());
 | |
| 
 | |
|         // if streamId is set, fetch other content
 | |
|         NodeRef streamNodeRef = info.getNodeRef();
 | |
|         if ((streamId != null) && (streamId.length() > 0))
 | |
|         {
 | |
|             CMISNodeInfo streamInfo = createNodeInfo(streamId);
 | |
|             if (!streamInfo.isVariant(CMISObjectVariant.CURRENT_VERSION))
 | |
|             {
 | |
|                 throw new CmisInvalidArgumentException("Stream id is invalid: " + streamId + ", expected variant " + CMISObjectVariant.CURRENT_VERSION + ", got variant " + streamInfo.getObjectVariant());
 | |
|             }
 | |
| 
 | |
|             streamNodeRef = streamInfo.getNodeRef();
 | |
|             type = streamInfo.getType();
 | |
|             checkDocumentTypeForContent(type);
 | |
|         }
 | |
| 
 | |
|         // get the stream now
 | |
|         try
 | |
|         {
 | |
|             ContentReader contentReader = contentService.getReader(streamNodeRef, ContentModel.PROP_CONTENT);
 | |
|             if (contentReader == null)
 | |
|             {
 | |
|                 throw new CmisConstraintException("Document has no content!");
 | |
|             }
 | |
| 
 | |
|             result.setMimeType(contentReader.getMimetype());
 | |
|             long contentSize = contentReader.getSize();
 | |
|             
 | |
|             if ((offset == null) && (length == null))
 | |
|             {
 | |
|                 result.setStream(contentReader.getContentInputStream());
 | |
|                 result.setLength(BigInteger.valueOf(contentSize));
 | |
|                 publishReadEvent(streamNodeRef, info.getName(), result.getMimeType(), contentSize, contentReader.getEncoding(), null);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 long off = (offset == null ? 0 : offset.longValue());
 | |
|                 long len = (length == null ? contentSize : length.longValue());
 | |
|                 if (off + len > contentSize)
 | |
|                 {
 | |
|                     len = contentReader.getSize() - off;
 | |
|                 }
 | |
| 
 | |
|                 result.setStream(new RangeInputStream(contentReader.getContentInputStream(), off, len));
 | |
|                 result.setLength(BigInteger.valueOf(len));
 | |
|                 publishReadEvent(streamNodeRef, info.getName(), result.getMimeType(), contentSize, contentReader.getEncoding(), off+" - "+len);
 | |
|             }
 | |
|         }
 | |
|         catch (Exception e)
 | |
|         {
 | |
|             if (e instanceof CmisBaseException)
 | |
|             {
 | |
|                 throw (CmisBaseException) e;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 StringBuilder msg = new StringBuilder("Failed to retrieve content: " + e.getMessage());
 | |
|                 Throwable cause = e.getCause();
 | |
|                 if(cause != null)
 | |
|                 {
 | |
|                     // add the cause to the CMIS exception
 | |
|                     msg.append(", ");
 | |
|                     msg.append(cause.getMessage());
 | |
|                 }
 | |
|                 throw new CmisRuntimeException(msg.toString(), e);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Notifies listeners that a read has taken place.
 | |
|      * 
 | |
|      * @param nodeRef NodeRef
 | |
|      * @param name String
 | |
|      * @param mimeType String
 | |
|      * @param contentSize long
 | |
|      * @param encoding String
 | |
|      * @param range String
 | |
|      */
 | |
|     protected void publishReadEvent(final NodeRef nodeRef, final String name, final String mimeType, final long contentSize, final String encoding, final String range)
 | |
|     {
 | |
|         final QName nodeType = nodeRef==null?null:nodeService.getType(nodeRef);
 | |
|         
 | |
|         eventPublisher.publishEvent(new EventPreparator(){
 | |
|             @Override
 | |
|             public Event prepareEvent(String user, String networkId, String transactionId)
 | |
|             {
 | |
|                 if (StringUtils.hasText(range))
 | |
|                 {
 | |
|                     return new ContentReadRangeEvent(user, networkId, transactionId,
 | |
|                                 nodeRef.getId(), null, nodeType.toString(), Client.asType(ClientType.cmis), name, mimeType, contentSize, encoding, range); 
 | |
|                 } 
 | |
|                 else 
 | |
|                 {
 | |
|                     return new ContentEventImpl(ContentEvent.DOWNLOAD, user, networkId, transactionId,
 | |
|                                 nodeRef.getId(), null, nodeType.toString(), Client.asType(ClientType.cmis), name, mimeType, contentSize, encoding);            
 | |
|                 }
 | |
|             }
 | |
|         });
 | |
|         
 | |
| 
 | |
|     }
 | |
| 
 | |
|     public void appendContent(CMISNodeInfo nodeInfo, ContentStream contentStream, boolean isLastChunk) throws IOException
 | |
|     {
 | |
|     	NodeRef nodeRef = nodeInfo.getNodeRef();
 | |
| 
 | |
|     	this.disableBehaviour(ContentModel.ASPECT_VERSIONABLE, nodeRef);
 | |
| 		
 | |
|     	if(!nodeService.hasAspect(nodeRef, ContentModel.ASPECT_CMIS_UPDATE_CONTEXT))
 | |
|     	{
 | |
|     		Map<QName, Serializable> props = new HashMap<QName, Serializable>();
 | |
|     		props.put(ContentModel.PROP_GOT_FIRST_CHUNK, true);
 | |
|     		nodeService.addAspect(nodeRef, ContentModel.ASPECT_CMIS_UPDATE_CONTEXT, props);
 | |
|     	}
 | |
| 
 | |
| 		ContentReader reader = contentService.getReader(nodeRef, ContentModel.PROP_CONTENT);
 | |
| 		InputStream existingContentInput = (reader != null ? reader.getContentInputStream() : null);
 | |
| 		InputStream input = contentStream.getStream();
 | |
| 
 | |
|     	ContentWriter writer = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
 | |
|     	OutputStream out = new BufferedOutputStream(writer.getContentOutputStream());
 | |
|     	
 | |
|     	InputStream in = null;
 | |
|     	if(existingContentInput != null)
 | |
|     	{
 | |
|     		in = new SequenceInputStream(existingContentInput, input);
 | |
|     	}
 | |
|     	else
 | |
|     	{
 | |
|     		in = input;
 | |
|     	}
 | |
| 
 | |
| 		try
 | |
| 		{
 | |
| 	    	IOUtils.copy(in, out);
 | |
| 
 | |
| 	    	if(isLastChunk)
 | |
| 	    	{
 | |
|     			nodeService.removeAspect(nodeRef, ContentModel.ASPECT_CMIS_UPDATE_CONTEXT);
 | |
| 	    		getActivityPoster().postFileFolderUpdated(nodeInfo.isFolder(), nodeRef);
 | |
| 
 | |
| 	    		createVersion(nodeRef, VersionType.MINOR, "Appended content stream");
 | |
| 	    	}
 | |
| 		}
 | |
| 		finally
 | |
| 		{
 | |
| 			if(in != null)
 | |
| 			{
 | |
| 				in.close();
 | |
| 			}
 | |
| 			if(out != null)
 | |
| 			{
 | |
|     	    	out.close();	
 | |
| 			}
 | |
| 			
 | |
| 			this.enableBehaviour(ContentModel.ASPECT_VERSIONABLE, nodeRef);
 | |
| 		}
 | |
|     }
 | |
| 
 | |
|     private void checkDocumentTypeForContent(TypeDefinitionWrapper type)
 | |
|     {
 | |
|         if (type == null)
 | |
|         {
 | |
|             throw new CmisObjectNotFoundException("No corresponding type found! Not a CMIS object?");
 | |
|         }
 | |
|         if (!(type instanceof DocumentTypeDefinitionWrapper))
 | |
|         {
 | |
|             throw new CmisStreamNotSupportedException("Object is not a document!");
 | |
|         }
 | |
|         if (((DocumentTypeDefinition) type.getTypeDefinition(false)).getContentStreamAllowed() == ContentStreamAllowed.NOTALLOWED)
 | |
|         {
 | |
|             throw new CmisConstraintException("Document cannot have content!");
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     private void addAspectProperties(CMISNodeInfo info, String filter, PropertiesImpl result)
 | |
|     {
 | |
|         if(getRequestCmisVersion().equals(CmisVersion.CMIS_1_1))
 | |
|         {
 | |
|             Set<String> propertyIds = new HashSet<String>();
 | |
|             Set<String> filterSet = splitFilter(filter);
 | |
|     
 | |
|             Set<QName> aspects = nodeService.getAspects(info.getNodeRef());
 | |
|             for (QName aspect : aspects)
 | |
|             {
 | |
|                 TypeDefinitionWrapper aspectType = getOpenCMISDictionaryService().findNodeType(aspect);
 | |
|                 if (aspectType == null)
 | |
|                 {
 | |
|                     continue;
 | |
|                 }
 | |
|     
 | |
|                 for (PropertyDefinitionWrapper propDef : aspectType.getProperties())
 | |
|                 {
 | |
|                     if (propertyIds.contains(propDef.getPropertyId()))
 | |
|                     {
 | |
|                         // skip properties that have already been added
 | |
|                         continue;
 | |
|                     }
 | |
|     
 | |
|                     if ((filterSet != null) && (!filterSet.contains(propDef.getPropertyDefinition().getQueryName())))
 | |
|                     {
 | |
|                         // skip properties that are not in the filter
 | |
|                         continue;
 | |
|                     }
 | |
|     
 | |
|                     Serializable value = propDef.getPropertyAccessor().getValue(info);
 | |
|                     result.addProperty(getProperty(propDef.getPropertyDefinition().getPropertyType(), propDef, value));
 | |
|     
 | |
|                     // mark property as 'added'
 | |
|                     propertyIds.add(propDef.getPropertyId());
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     public Properties getNodeProperties(CMISNodeInfo info, String filter)
 | |
|     {
 | |
|         PropertiesImpl result = new PropertiesImpl();
 | |
| 
 | |
|         Set<String> filterSet = splitFilter(filter);
 | |
| 
 | |
|         for (PropertyDefinitionWrapper propDef : info.getType().getProperties())
 | |
|         {
 | |
|             if (!propDef.getPropertyId().equals(PropertyIds.OBJECT_ID))
 | |
|             {
 | |
|                 // don't filter the object id
 | |
|                 if ((filterSet != null) && (!filterSet.contains(propDef.getPropertyDefinition().getQueryName())))
 | |
|                 {
 | |
|                     // skip properties that are not in the filter
 | |
|                     continue;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             Serializable value = propDef.getPropertyAccessor().getValue(info);
 | |
|             result.addProperty(getProperty(propDef.getPropertyDefinition().getPropertyType(), propDef, value));
 | |
|         }
 | |
| 
 | |
|         addAspectProperties(info, filter, result);
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     public Properties getNodeProperties(CMISNodeInfo info, FileInfo node, String filter, TypeDefinitionWrapper type)
 | |
|     {
 | |
|         PropertiesImpl result = new PropertiesImpl();
 | |
| 
 | |
|         Set<String> filterSet = splitFilter(filter);
 | |
| 
 | |
|         Map<QName, Serializable> nodeProps = node.getProperties();
 | |
| 
 | |
|         for (PropertyDefinitionWrapper propDef : type.getProperties())
 | |
|         {
 | |
|             if (!propDef.getPropertyId().equals(PropertyIds.OBJECT_ID))
 | |
|             {
 | |
|                 // don't filter the object id
 | |
|                 if ((filterSet != null) && (!filterSet.contains(propDef.getPropertyDefinition().getQueryName())))
 | |
|                 {
 | |
|                     // skip properties that are not in the filter
 | |
|                     continue;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             Serializable value = null;
 | |
| 
 | |
|             CMISPropertyAccessor accessor = propDef.getPropertyAccessor();
 | |
|             if (accessor instanceof DirectProperty)
 | |
|             {
 | |
|                 value = nodeProps.get(accessor.getMappedProperty());
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 value = propDef.getPropertyAccessor().getValue(info);
 | |
|             }
 | |
| 
 | |
|             result.addProperty(getProperty(propDef.getPropertyDefinition().getPropertyType(), propDef, value));
 | |
|         }
 | |
| 
 | |
|         addAspectProperties(info, filter, result);
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     public Properties getAssocProperties(CMISNodeInfo info, String filter)
 | |
|     {
 | |
|         PropertiesImpl result = new PropertiesImpl();
 | |
| 
 | |
|         Set<String> filterSet = splitFilter(filter);
 | |
| 
 | |
|         for (PropertyDefinitionWrapper propDefWrap : info.getType().getProperties())
 | |
|         {
 | |
|             PropertyDefinition<?> propDef = propDefWrap.getPropertyDefinition();
 | |
|             if ((filterSet != null) && (!filterSet.contains(propDef.getQueryName())))
 | |
|             {
 | |
|                 // skip properties that are not in the filter
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             CMISPropertyAccessor cmisPropertyAccessor = propDefWrap.getPropertyAccessor();
 | |
|             Serializable value = cmisPropertyAccessor.getValue(info);
 | |
|             PropertyType propType = propDef.getPropertyType();
 | |
|             PropertyData<?> propertyData = getProperty(propType, propDefWrap, value);
 | |
|             result.addProperty(propertyData);
 | |
|         }
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Builds aspect extension.
 | |
|      */
 | |
|     public List<CmisExtensionElement> getAspectExtensions(CMISNodeInfo info, String filter,
 | |
|             Set<String> alreadySetProperties)
 | |
|     {
 | |
|         List<CmisExtensionElement> extensions = new ArrayList<CmisExtensionElement>();
 | |
|         Set<String> propertyIds = new HashSet<String>(alreadySetProperties);
 | |
|         List<CmisExtensionElement> propertyExtensionList = new ArrayList<CmisExtensionElement>();
 | |
|         Set<String> filterSet = splitFilter(filter);
 | |
| 
 | |
|         Set<QName> aspects = nodeService.getAspects(info.getNodeRef());
 | |
|         for (QName aspect : aspects)
 | |
|         {
 | |
|             TypeDefinitionWrapper aspectType = getOpenCMISDictionaryService().findNodeType(aspect);
 | |
|             if (aspectType == null)
 | |
|             {
 | |
|                 continue;
 | |
|             }
 | |
|             
 | |
|             AspectDefinition aspectDefinition = dictionaryService.getAspect(aspect);
 | |
|             Map<QName, org.alfresco.service.cmr.dictionary.PropertyDefinition> aspectProperties = aspectDefinition.getProperties();
 | |
| 
 | |
|             extensions.add(new CmisExtensionElementImpl(ALFRESCO_EXTENSION_NAMESPACE, APPLIED_ASPECTS, null, aspectType
 | |
|                     .getTypeId()));
 | |
| 
 | |
|             for (PropertyDefinitionWrapper propDef : aspectType.getProperties())
 | |
|             {
 | |
|                 boolean addPropertyToExtensionList = getRequestCmisVersion().equals(CmisVersion.CMIS_1_1) && aspectProperties.keySet().contains(propDef.getAlfrescoName());
 | |
|                 // MNT-11876 : add property to extension even if it has been returned (CMIS 1.1)
 | |
|                 if (propertyIds.contains(propDef.getPropertyId()) && !addPropertyToExtensionList)
 | |
|                 {
 | |
|                     // skip properties that have already been added
 | |
|                     continue;
 | |
|                 }
 | |
| 
 | |
|                 if ((filterSet != null) && (!filterSet.contains(propDef.getPropertyDefinition().getQueryName())))
 | |
|                 {
 | |
|                     // skip properties that are not in the filter
 | |
|                     continue;
 | |
|                 }
 | |
| 
 | |
|                 Serializable value = propDef.getPropertyAccessor().getValue(info);
 | |
|                 propertyExtensionList.add(createAspectPropertyExtension(propDef.getPropertyDefinition(), value));
 | |
| 
 | |
|                 // mark property as 'added'
 | |
|                 propertyIds.add(propDef.getPropertyId());
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if (!propertyExtensionList.isEmpty())
 | |
|         {
 | |
|             CmisExtensionElementImpl propertiesExtension = new CmisExtensionElementImpl(
 | |
|                     ALFRESCO_EXTENSION_NAMESPACE, "properties", null, propertyExtensionList);
 | |
|             extensions.addAll(Collections.singletonList(propertiesExtension));
 | |
|         }
 | |
| 
 | |
|         return extensions;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Creates a property extension element.
 | |
|      */
 | |
|     @SuppressWarnings("rawtypes")
 | |
|     private CmisExtensionElement createAspectPropertyExtension(PropertyDefinition<?> propertyDefinition, Object value)
 | |
|     {
 | |
|         String name;
 | |
|         switch (propertyDefinition.getPropertyType())
 | |
|         {
 | |
|         case BOOLEAN:
 | |
|             name = "propertyBoolean";
 | |
|             break;
 | |
|         case DATETIME:
 | |
|             name = "propertyDateTime";
 | |
|             break;
 | |
|         case DECIMAL:
 | |
|             name = "propertyDecimal";
 | |
|             break;
 | |
|         case INTEGER:
 | |
|             name = "propertyInteger";
 | |
|             break;
 | |
|         case ID:
 | |
|             name = "propertyId";
 | |
|             break;
 | |
|         default:
 | |
|             name = "propertyString";
 | |
|         }
 | |
| 
 | |
|         Map<String, String> attributes = new HashMap<String, String>();
 | |
|         attributes.put("propertyDefinitionId", propertyDefinition.getId());
 | |
|         attributes.put("queryName", propertyDefinition.getQueryName());
 | |
|         // optional value
 | |
|         if (propertyDefinition.getDisplayName() !=null && propertyDefinition.getDisplayName().trim().length() > 0)
 | |
|         {
 | |
|             attributes.put("displayName", propertyDefinition.getDisplayName());
 | |
|         }
 | |
|         // optional value
 | |
|         if (propertyDefinition.getLocalName() !=null && propertyDefinition.getLocalName().trim().length() > 0)
 | |
|         {
 | |
|             attributes.put("localName", propertyDefinition.getLocalName());
 | |
|         }
 | |
|         
 | |
| 
 | |
|         List<CmisExtensionElement> propertyValues = new ArrayList<CmisExtensionElement>();
 | |
|         if (value != null)
 | |
|         {
 | |
|             if (value instanceof List)
 | |
|             {
 | |
|                 for (Object o : ((List) value))
 | |
|                 {
 | |
|                 	if(o != null)
 | |
|                 	{
 | |
|                 		propertyValues.add(new CmisExtensionElementImpl(CMIS_NAMESPACE, "value", null,
 | |
|                 				convertAspectPropertyValue(o)));
 | |
|                 	}
 | |
|                 	else
 | |
|                 	{
 | |
|                 		logger.warn("Unexpected null entry in list value for property " + propertyDefinition.getDisplayName()
 | |
|                 				+ ", value = " + value);
 | |
|                 	}
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 propertyValues.add(new CmisExtensionElementImpl(CMIS_NAMESPACE, "value", null,
 | |
|                         convertAspectPropertyValue(value)));
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return new CmisExtensionElementImpl(CMIS_NAMESPACE, name, attributes, propertyValues);
 | |
|     }
 | |
| 
 | |
|     private String convertAspectPropertyValue(Object value)
 | |
|     {
 | |
|         if (value instanceof Date)
 | |
|         {
 | |
|             GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
 | |
|             cal.setTime((Date) value);
 | |
|             value = cal;
 | |
|         }
 | |
| 
 | |
|         if (value instanceof GregorianCalendar)
 | |
|         {
 | |
|             DatatypeFactory df;
 | |
|             try
 | |
|             {
 | |
|                 df = DatatypeFactory.newInstance();
 | |
|             }
 | |
|             catch (DatatypeConfigurationException e)
 | |
|             {
 | |
|                 throw new IllegalArgumentException("Aspect conversation exception: " + e.getMessage(), e);
 | |
|             }
 | |
|             return df.newXMLGregorianCalendar((GregorianCalendar) value).toXMLFormat();
 | |
|         }
 | |
| 
 | |
|         // MNT-12496
 | |
|         // Encode for AtomPub only. Browser/json binding already encodes.
 | |
|         if (AlfrescoCmisServiceCall.get() != null && CallContext.BINDING_ATOMPUB.equals(AlfrescoCmisServiceCall.get().getBinding()))
 | |
|         {
 | |
|         	return escapeControlCharacters(value.toString());
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|         	return value.toString();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @SuppressWarnings("unchecked")
 | |
|     private AbstractPropertyData<?> getProperty(PropertyType propType, PropertyDefinitionWrapper propDef,
 | |
|             Serializable value)
 | |
|     {
 | |
|         AbstractPropertyData<?> result = null;
 | |
|         switch (propType)
 | |
|         {
 | |
|         case BOOLEAN:
 | |
|             result = new PropertyBooleanImpl();
 | |
|             if (value instanceof List)
 | |
|             {
 | |
|                 ((PropertyBooleanImpl) result).setValues((List<Boolean>) value);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 ((PropertyBooleanImpl) result).setValue((Boolean) value);
 | |
|             }
 | |
|             break;
 | |
|         case DATETIME:
 | |
|             result = new PropertyDateTimeImpl();
 | |
|             if (value instanceof List)
 | |
|             {
 | |
|                 ((PropertyDateTimeImpl) result).setValues((List<GregorianCalendar>) DefaultTypeConverter.INSTANCE
 | |
|                         .convert(GregorianCalendar.class, (List<?>) value));
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 ((PropertyDateTimeImpl) result).setValue(DefaultTypeConverter.INSTANCE.convert(GregorianCalendar.class,
 | |
|                         value));
 | |
|             }
 | |
|             break;
 | |
|         case DECIMAL:
 | |
|             result = new PropertyDecimalImpl();
 | |
|             if (value instanceof List)
 | |
|             {
 | |
|                 ((PropertyDecimalImpl) result).setValues((List<BigDecimal>) DefaultTypeConverter.INSTANCE.convert(
 | |
|                         BigDecimal.class, (List<?>) value));
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 ((PropertyDecimalImpl) result).setValue(DefaultTypeConverter.INSTANCE.convert(BigDecimal.class, value));
 | |
|             }
 | |
|             break;
 | |
|         case HTML:
 | |
|             result = new PropertyHtmlImpl();
 | |
|             if (value instanceof List)
 | |
|             {
 | |
|                 ((PropertyHtmlImpl) result).setValues((List<String>) value);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 ((PropertyHtmlImpl) result).setValue((String) value);
 | |
|             }
 | |
|             break;
 | |
|         case ID:
 | |
|             result = new PropertyIdImpl();
 | |
|             if (value instanceof List)
 | |
|             {
 | |
|                 ((PropertyIdImpl) result).setValues((List<String>) value);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if (value instanceof NodeRef)
 | |
|                 {
 | |
|                     ((PropertyIdImpl) result).setValue(constructObjectId((NodeRef)value, null));
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     ((PropertyIdImpl) result).setValue((String) value);
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         case INTEGER:
 | |
|             result = new PropertyIntegerImpl();
 | |
|             if (value instanceof List)
 | |
|             {
 | |
|                 ((PropertyIntegerImpl) result).setValues((List<BigInteger>) DefaultTypeConverter.INSTANCE.convert(
 | |
|                         BigInteger.class, (List<?>) value));
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 ((PropertyIntegerImpl) result).setValue(DefaultTypeConverter.INSTANCE.convert(BigInteger.class, value));
 | |
|             }
 | |
|             break;
 | |
|         case STRING:
 | |
|             result = new PropertyStringImpl();
 | |
|             if (value instanceof List)
 | |
|             {
 | |
|                 ((PropertyStringImpl) result).setValues((List<String>) value);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                // MNT-12496
 | |
|                // Encode for AtomPub only. Browser/json binding already encodes.
 | |
|             	if (AlfrescoCmisServiceCall.get() != null && CallContext.BINDING_ATOMPUB.equals(AlfrescoCmisServiceCall.get().getBinding()))
 | |
|             	{
 | |
|             		((PropertyStringImpl) result).setValue(escapeControlCharacters((String) value));
 | |
|             	}
 | |
|             	else
 | |
|             	{
 | |
|             		((PropertyStringImpl) result).setValue((String) value);
 | |
|             	}
 | |
|             }
 | |
|             break;
 | |
|         case URI:
 | |
|             result = new PropertyUriImpl();
 | |
|             if (value instanceof List)
 | |
|             {
 | |
|                 ((PropertyUriImpl) result).setValues((List<String>) value);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 ((PropertyUriImpl) result).setValue((String) value);
 | |
|             }
 | |
|             break;
 | |
|         default:
 | |
|             throw new RuntimeException("Unknown datatype! Spec change?");
 | |
|         }
 | |
| 
 | |
|         if (propDef != null)
 | |
|         {
 | |
|             result.setId(propDef.getPropertyDefinition().getId());
 | |
|             result.setQueryName(propDef.getPropertyDefinition().getQueryName());
 | |
|             result.setDisplayName(propDef.getPropertyDefinition().getDisplayName());
 | |
|             result.setLocalName(propDef.getPropertyDefinition().getLocalName());
 | |
|         }
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
|     
 | |
|     private String escapeControlCharacters(String origValue)
 | |
|     {
 | |
|         if (origValue == null)
 | |
|         {
 | |
|             return origValue;
 | |
|         }
 | |
|         StringBuilder sb = new StringBuilder();
 | |
| 
 | |
|         for (int i = 0; i < origValue.length(); i++)
 | |
|         {
 | |
|             char ch = origValue.charAt(i);
 | |
|             switch (ch)
 | |
|             {
 | |
|             case '\b':
 | |
|             case '\f':
 | |
|             case '\n':
 | |
|             case '\r':
 | |
|             case '\t':
 | |
|                 sb.append(ch);
 | |
|                 break;
 | |
|             default:
 | |
|                 // Reference: http://www.unicode.org/versions/Unicode5.1.0/
 | |
|                 if ((ch >= '\u0000' && ch <= '\u001F') || (ch >= '\u007F' && ch <= '\u009F') || (ch >= '\u2000' && ch <= '\u20FF'))
 | |
|                 {
 | |
|                     String ss = Integer.toHexString(ch);
 | |
|                     sb.append("\\u");
 | |
|                     for (int k = 0; k < 4 - ss.length(); k++)
 | |
|                     {
 | |
|                         sb.append('0');
 | |
|                     }
 | |
|                     sb.append(ss.toUpperCase());
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     sb.append(ch);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         return sb.toString();
 | |
|     }
 | |
| 
 | |
|     private Set<String> splitFilter(String filter)
 | |
|     {
 | |
|         if (filter == null)
 | |
|         {
 | |
|             return null;
 | |
|         }
 | |
| 
 | |
|         if (filter.trim().length() == 0)
 | |
|         {
 | |
|             return null;
 | |
|         }
 | |
| 
 | |
|         Set<String> result = new HashSet<String>();
 | |
|         for (String s : filter.split(","))
 | |
|         {
 | |
|             s = s.trim();
 | |
|             if (s.equals("*"))
 | |
|             {
 | |
|                 return null;
 | |
|             }
 | |
|             else if (s.length() > 0)
 | |
|             {
 | |
|                 result.add(s);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // set a few base properties
 | |
|         result.add(QUERY_NAME_OBJECT_ID);
 | |
|         result.add(QUERY_NAME_OBJECT_TYPE_ID);
 | |
|         result.add(QUERY_NAME_BASE_TYPE_ID);
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     public AllowableActions getAllowableActions(CMISNodeInfo info)
 | |
|     {
 | |
|         AllowableActionsImpl result = new AllowableActionsImpl();
 | |
|         Set<Action> allowableActions = new HashSet<Action>();
 | |
|         result.setAllowableActions(allowableActions);
 | |
| 
 | |
|         for (CMISActionEvaluator evaluator : info.getType().getActionEvaluators().values())
 | |
|         {
 | |
|             if (evaluator.isAllowed(info))
 | |
|             {
 | |
|                 allowableActions.add(evaluator.getAction());
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     public List<ObjectData> getRelationships(NodeRef nodeRef, IncludeRelationships includeRelationships/*, CmisVersion cmisVersion*/)
 | |
|     {
 | |
|         List<ObjectData> result = new ArrayList<ObjectData>();
 | |
| 
 | |
|         if (nodeRef.getStoreRef().getProtocol().equals(VersionBaseModel.STORE_PROTOCOL))
 | |
|         {
 | |
|             // relationships from and to versions are not preserved
 | |
|             return result;
 | |
|         }
 | |
| 
 | |
|         // get relationships
 | |
|         List<AssociationRef> assocs = new ArrayList<AssociationRef>();
 | |
|         if (includeRelationships == IncludeRelationships.SOURCE || includeRelationships == IncludeRelationships.BOTH)
 | |
|         {
 | |
|             assocs.addAll(nodeService.getTargetAssocs(nodeRef, RegexQNamePattern.MATCH_ALL));
 | |
|         }
 | |
|         if (includeRelationships == IncludeRelationships.TARGET || includeRelationships == IncludeRelationships.BOTH)
 | |
|         {
 | |
|             assocs.addAll(nodeService.getSourceAssocs(nodeRef, RegexQNamePattern.MATCH_ALL));
 | |
|         }
 | |
| 
 | |
|         // filter relationships that not map the CMIS domain model
 | |
|         for (AssociationRef assocRef : assocs)
 | |
|         {
 | |
|             TypeDefinitionWrapper assocTypeDef = getOpenCMISDictionaryService().findAssocType(assocRef.getTypeQName());
 | |
|             if (assocTypeDef == null || getType(assocRef.getSourceRef()) == null
 | |
|                     || getType(assocRef.getTargetRef()) == null)
 | |
|             {
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             try
 | |
|             {
 | |
| 	            result.add(createCMISObject(createNodeInfo(assocRef), null, false, IncludeRelationships.NONE,
 | |
| 	                    RENDITION_NONE, false, false/*, cmisVersion*/));
 | |
|             }
 | |
|             catch(AccessDeniedException e)
 | |
|             {
 | |
|             	// PUBLICAPI-110
 | |
|             	// ok, just skip it
 | |
|             }
 | |
|             catch(CmisObjectNotFoundException e)
 | |
|             {
 | |
|                 // ignore objects that have not been found (perhaps because their type is unknown to CMIS)
 | |
|             }
 | |
|             // TODO: Somewhere this has not been wrapped correctly
 | |
|             catch (net.sf.acegisecurity.AccessDeniedException e)
 | |
|             {
 | |
|                 // skip
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     public ObjectList getObjectRelationships(NodeRef nodeRef, RelationshipDirection relationshipDirection,
 | |
|             String typeId, String filter, Boolean includeAllowableActions, BigInteger maxItems, BigInteger skipCount)
 | |
|     {
 | |
|         ObjectListImpl result = new ObjectListImpl();
 | |
|         result.setHasMoreItems(false);
 | |
|         result.setNumItems(BigInteger.ZERO);
 | |
|         result.setObjects(new ArrayList<ObjectData>());
 | |
| 
 | |
|         if (nodeRef.getStoreRef().getProtocol().equals(VersionBaseModel.STORE_PROTOCOL))
 | |
|         {
 | |
|             // relationships from and to versions are not preserved
 | |
|             return result;
 | |
|         }
 | |
| 
 | |
|         // get relationships
 | |
|         List<AssociationRef> assocs = new ArrayList<AssociationRef>();
 | |
|         if (relationshipDirection == RelationshipDirection.SOURCE
 | |
|                 || relationshipDirection == RelationshipDirection.EITHER)
 | |
|         {
 | |
|             assocs.addAll(nodeService.getTargetAssocs(nodeRef, RegexQNamePattern.MATCH_ALL));
 | |
|         }
 | |
|         if (relationshipDirection == RelationshipDirection.TARGET
 | |
|                 || relationshipDirection == RelationshipDirection.EITHER)
 | |
|         {
 | |
|             assocs.addAll(nodeService.getSourceAssocs(nodeRef, RegexQNamePattern.MATCH_ALL));
 | |
|         }
 | |
| 
 | |
|         int skip = (skipCount == null ? 0 : skipCount.intValue());
 | |
|         int max = (maxItems == null ? Integer.MAX_VALUE : maxItems.intValue());
 | |
|         int counter = 0;
 | |
|         boolean hasMore = false;
 | |
| 
 | |
|         if (max > 0)
 | |
|         {
 | |
|             // filter relationships that not map the CMIS domain model
 | |
|             for (AssociationRef assocRef : assocs)
 | |
|             {
 | |
|                 TypeDefinitionWrapper assocTypeDef = getOpenCMISDictionaryService().findAssocType(assocRef.getTypeQName());
 | |
|                 if (assocTypeDef == null || getType(assocRef.getSourceRef()) == null
 | |
|                         || getType(assocRef.getTargetRef()) == null)
 | |
|                 {
 | |
|                     continue;
 | |
|                 }
 | |
| 
 | |
|                 if ((typeId != null) && !assocTypeDef.getTypeId().equals(typeId))
 | |
|                 {
 | |
|                     continue;
 | |
|                 }
 | |
| 
 | |
|                 counter++;
 | |
| 
 | |
|                 if (skip > 0)
 | |
|                 {
 | |
|                     skip--;
 | |
|                     continue;
 | |
|                 }
 | |
| 
 | |
|                 max--;
 | |
|                 if (max > 0)
 | |
|                 {
 | |
|                 	try
 | |
|                 	{
 | |
| 	                    result.getObjects().add(
 | |
| 	                            createCMISObject(createNodeInfo(assocRef), filter, includeAllowableActions,
 | |
| 	                                    IncludeRelationships.NONE, RENDITION_NONE, false, false/*, cmisVersion*/));
 | |
|                     }
 | |
|                     catch(CmisObjectNotFoundException e)
 | |
|                     {
 | |
|                         // ignore objects that have not been found (perhaps because their type is unknown to CMIS)
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     hasMore = true;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         result.setNumItems(BigInteger.valueOf(counter));
 | |
|         result.setHasMoreItems(hasMore);
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     public List<RenditionData> getRenditions(NodeRef nodeRef, String renditionFilter, BigInteger maxItems,
 | |
|             BigInteger skipCount)
 | |
|     {
 | |
|         CMISRenditionMapping mapping = getRenditionMapping();
 | |
|         return mapping.getRenditions(nodeRef, renditionFilter, maxItems, skipCount);
 | |
|     }
 | |
| 
 | |
|     public Acl getACL(NodeRef nodeRef, boolean onlyBasicPermissions)
 | |
|     {
 | |
|         AccessControlListImpl result = new AccessControlListImpl();
 | |
| 
 | |
|         // get the permissions and sort them
 | |
|         ArrayList<AccessPermission> ordered = new ArrayList<AccessPermission>(
 | |
|                 permissionService.getAllSetPermissions(nodeRef));
 | |
|         Collections.sort(ordered, new AccessPermissionComparator());
 | |
| 
 | |
|         // remove denied permissions and create OpenCMIS objects
 | |
|         Map<String, Map<Boolean, AccessControlEntryImpl>> aceMap = new HashMap<String, Map<Boolean, AccessControlEntryImpl>>();
 | |
|         for (AccessPermission entry : ordered)
 | |
|         {
 | |
|             if (entry.getAccessStatus() == AccessStatus.ALLOWED)
 | |
|             {
 | |
|                 // add allowed entries
 | |
|                 Map<Boolean, AccessControlEntryImpl> directAce = aceMap.get(entry.getAuthority());
 | |
|                 if (directAce == null)
 | |
|                 {
 | |
|                     directAce = new HashMap<Boolean, AccessControlEntryImpl>();
 | |
|                     aceMap.put(entry.getAuthority(), directAce);
 | |
|                 }
 | |
| 
 | |
|                 AccessControlEntryImpl ace = directAce.get(entry.isSetDirectly());
 | |
|                 if (ace == null)
 | |
|                 {
 | |
|                     ace = new AccessControlEntryImpl();
 | |
|                     ace.setPrincipal(new AccessControlPrincipalDataImpl(entry.getAuthority()));
 | |
|                     ace.setPermissions(new ArrayList<String>());
 | |
|                     ace.setDirect(entry.isSetDirectly());
 | |
|                     directAce.put(entry.isSetDirectly(), ace);
 | |
|                 }
 | |
| 
 | |
|                 ace.getPermissions().add(entry.getPermission());
 | |
|             }
 | |
|             else if (entry.getAccessStatus() == AccessStatus.DENIED)
 | |
|             {
 | |
|                 // remove denied entries
 | |
|                 Map<Boolean, AccessControlEntryImpl> directAce = aceMap.get(entry.getAuthority());
 | |
|                 if (directAce != null)
 | |
|                 {
 | |
|                     for (AccessControlEntryImpl ace : directAce.values())
 | |
|                     {
 | |
|                         ace.getPermissions().remove(entry.getPermission());
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // adjust permissions, add CMIS permissions and add ACEs to ACL
 | |
|         List<Ace> aces = new ArrayList<Ace>();
 | |
|         result.setAces(aces);
 | |
|         for (Map<Boolean, AccessControlEntryImpl> bothAces : aceMap.values())
 | |
|         {
 | |
|             // get, translate and set direct ACE
 | |
|             AccessControlEntryImpl directAce = bothAces.get(true);
 | |
|             if ((directAce != null) && (!directAce.getPermissions().isEmpty()))
 | |
|             {
 | |
|             	List<String> permissions = translatePermissionsToCMIS(directAce.getPermissions(), onlyBasicPermissions);
 | |
|             	if(permissions != null && !permissions.isEmpty())
 | |
|             	{
 | |
|                 	// tck doesn't like empty permissions list
 | |
| 	                directAce.setPermissions(permissions);
 | |
| 	                aces.add(directAce);
 | |
|             	}
 | |
|             }
 | |
| 
 | |
|             // get, translate, remove duplicate permissions and set indirect ACE
 | |
|             AccessControlEntryImpl indirectAce = bothAces.get(false);
 | |
|             if ((indirectAce != null) && (!indirectAce.getPermissions().isEmpty()))
 | |
|             {
 | |
|             	List<String> permissions = translatePermissionsToCMIS(indirectAce.getPermissions(), onlyBasicPermissions);
 | |
|                 indirectAce.setPermissions(permissions);
 | |
| 
 | |
|                 // remove permissions that are already set in the direct ACE
 | |
|                 if ((directAce != null) && (!directAce.getPermissions().isEmpty()))
 | |
|                 {
 | |
|                     indirectAce.getPermissions().removeAll(directAce.getPermissions());
 | |
|                 }
 | |
| 
 | |
|                 if(!indirectAce.getPermissions().isEmpty())
 | |
|                 {
 | |
|                 	// tck doesn't like empty permissions list
 | |
|                 	aces.add(indirectAce);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         result.setExact(!onlyBasicPermissions);
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     private List<String> translatePermissionsToCMIS(List<String> permissions, boolean onlyBasicPermissions)
 | |
|     {
 | |
|         Set<String> result = new TreeSet<String>();
 | |
| 
 | |
|         for (String permission : permissions)
 | |
|         {
 | |
|             PermissionReference permissionReference = permissionModelDao.getPermissionReference(null, permission);
 | |
| 
 | |
|             if (onlyBasicPermissions)
 | |
|             {
 | |
| 
 | |
|                 // check for full permissions
 | |
|                 if (permissionModelDao.hasFull(permissionReference))
 | |
|                 {
 | |
|                     result.add(BasicPermissions.ALL);
 | |
|                 }
 | |
| 
 | |
|                 // check short forms
 | |
|                 Set<PermissionReference> longForms = permissionModelDao.getGranteePermissions(permissionReference);
 | |
| 
 | |
|                 HashSet<String> shortForms = new HashSet<String>();
 | |
|                 for (PermissionReference longForm : longForms)
 | |
|                 {
 | |
|                     shortForms.add(permissionModelDao.isUnique(longForm) ? longForm.getName() : longForm.toString());
 | |
|                 }
 | |
| 
 | |
|                 for (String perm : shortForms)
 | |
|                 {
 | |
|                     if (PermissionService.READ.equals(perm))
 | |
|                     {
 | |
|                         result.add(BasicPermissions.READ);
 | |
|                     }
 | |
|                     else if (PermissionService.WRITE.equals(perm))
 | |
|                     {
 | |
|                         result.add(BasicPermissions.WRITE);
 | |
|                     }
 | |
|                     else if (PermissionService.ALL_PERMISSIONS.equals(perm))
 | |
|                     {
 | |
|                         result.add(BasicPermissions.ALL);
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 // check the permission
 | |
|                 if (PermissionService.READ.equals(permission))
 | |
|                 {
 | |
|                     result.add(BasicPermissions.READ);
 | |
|                 }
 | |
|                 else if (PermissionService.WRITE.equals(permission))
 | |
|                 {
 | |
|                     result.add(BasicPermissions.WRITE);
 | |
|                 }
 | |
|                 else if (PermissionService.ALL_PERMISSIONS.equals(permission))
 | |
|                 {
 | |
|                     result.add(BasicPermissions.ALL);
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 // ACE-2224: only repository specific permissions should be reported
 | |
|                 if (permission.startsWith("{"))
 | |
|                 {
 | |
|                     result.add(permission);
 | |
|                 }
 | |
|                 // do revert conversion for basic permissions that have exact matching
 | |
|                 else if (PermissionService.READ.equals(permission))
 | |
|                 {
 | |
|                     result.add(BasicPermissions.READ);
 | |
|                 }
 | |
|                 else if (PermissionService.WRITE.equals(permission))
 | |
|                 {
 | |
|                     result.add(BasicPermissions.WRITE);
 | |
|                 }
 | |
|                 else if (PermissionService.ALL_PERMISSIONS.equals(permission))
 | |
|                 {
 | |
|                     result.add(BasicPermissions.ALL);
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     result.add(permissionReference.toString());
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return new ArrayList<String>(result);
 | |
|     }
 | |
| 
 | |
|     public static class AccessPermissionComparator implements Comparator<AccessPermission>
 | |
|     {
 | |
|         public int compare(AccessPermission left, AccessPermission right)
 | |
|         {
 | |
|             if (left.getPosition() != right.getPosition())
 | |
|             {
 | |
|                 return right.getPosition() - left.getPosition();
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if (left.getAccessStatus() != right.getAccessStatus())
 | |
|                 {
 | |
|                     return (left.getAccessStatus() == AccessStatus.DENIED) ? -1 : 1;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     int compare = left.getAuthority().compareTo(right.getAuthority());
 | |
|                     if (compare != 0)
 | |
|                     {
 | |
|                         return compare;
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         return (left.getPermission().compareTo(right.getPermission()));
 | |
|                     }
 | |
| 
 | |
|                 }
 | |
| 
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Applies the given ACLs.
 | |
|      */
 | |
|     public void applyACL(NodeRef nodeRef, TypeDefinitionWrapper type, Acl addAces, Acl removeAces)
 | |
|     {
 | |
|         boolean hasAdd = (addAces != null) && (addAces.getAces() != null) && !addAces.getAces().isEmpty();
 | |
|         boolean hasRemove = (removeAces != null) && (removeAces.getAces() != null) && !removeAces.getAces().isEmpty();
 | |
| 
 | |
|         if (!hasAdd && !hasRemove)
 | |
|         {
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         if (!type.getTypeDefinition(false).isControllableAcl())
 | |
|         {
 | |
|             throw new CmisConstraintException("Object is not ACL controllable!");
 | |
|         }
 | |
| 
 | |
|         // remove permissions
 | |
|         if (hasRemove)
 | |
|         {
 | |
|             Set<AccessPermission> permissions = permissionService.getAllSetPermissions(nodeRef);
 | |
| 
 | |
|             // get only direct ACE since only those can be removed
 | |
|             Acl onlyDirectAcl = excludeInheritedAces(nodeRef, removeAces);
 | |
| 
 | |
|             for (Ace ace : onlyDirectAcl.getAces())
 | |
|             {
 | |
|                 String principalId = ace.getPrincipalId();
 | |
|                 if (CMIS_USER.equals(principalId))
 | |
|                 {
 | |
|                     principalId = AuthenticationUtil.getFullyAuthenticatedUser();
 | |
|                 }
 | |
| 
 | |
|                 for (String permission : translatePermissionsFromCMIS(ace.getPermissions()))
 | |
|                 {
 | |
| 
 | |
|                     AccessPermission toCheck = new AccessPermissionImpl(permission, AccessStatus.ALLOWED, principalId,
 | |
|                             0);
 | |
|                     if (!permissions.contains(toCheck))
 | |
|                     {
 | |
|                         throw new CmisConstraintException("No matching ACE found to remove!");
 | |
|                     }
 | |
| 
 | |
|                     permissionService.deletePermission(nodeRef, principalId, permission);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // add permissions
 | |
|         if (hasAdd)
 | |
|         {
 | |
|             for (Ace ace : addAces.getAces())
 | |
|             {
 | |
|                 String principalId = ace.getPrincipalId();
 | |
|                 if (CMIS_USER.equals(principalId))
 | |
|                 {
 | |
|                     principalId = AuthenticationUtil.getFullyAuthenticatedUser();
 | |
|                 }
 | |
| 
 | |
|                 for (String permission : translatePermissionsFromCMIS(ace.getPermissions()))
 | |
|                 {
 | |
|                     permissionService.setPermission(nodeRef, principalId, permission, true);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Converts Acl to map and ignore the indirect ACEs
 | |
|      * 
 | |
|      * @param acl Acl
 | |
|      * @return Map
 | |
|      */
 | |
|     private Map<String, Set<String>> convertAclToMap(Acl acl)
 | |
|     {
 | |
|         Map<String, Set<String>> result = new HashMap<String, Set<String>>();
 | |
| 
 | |
|         if (acl == null || acl.getAces() == null)
 | |
|         {
 | |
|             return result;
 | |
|         }
 | |
| 
 | |
|         for (Ace ace : acl.getAces())
 | |
|         {
 | |
|             // don't consider indirect ACEs - we can't change them
 | |
|             if (!ace.isDirect())
 | |
|             {
 | |
|                 // ignore
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             // although a principal must not be null, check it
 | |
|             if (ace.getPrincipal() == null || ace.getPrincipal().getId() == null)
 | |
|             {
 | |
|                 // ignore
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             Set<String> permissions = result.get(ace.getPrincipal().getId());
 | |
|             if (permissions == null)
 | |
|             {
 | |
|                 permissions = new HashSet<String>();
 | |
|                 result.put(ace.getPrincipal().getId(), permissions);
 | |
|             }
 | |
| 
 | |
|             if (ace.getPermissions() != null)
 | |
|             {
 | |
|                 permissions.addAll(ace.getPermissions());
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Filter acl to ignore inherited ACEs
 | |
|      * 
 | |
|      * @param nodeRef NodeRef
 | |
|      * @param acl Acl
 | |
|      * @return Acl
 | |
|      */
 | |
|     protected Acl excludeInheritedAces(NodeRef nodeRef, Acl acl)
 | |
|     {
 | |
| 
 | |
|         List<Ace> newAces = new ArrayList<Ace>();
 | |
|         Acl allACLs = getACL(nodeRef, false);
 | |
| 
 | |
|         Map<String, Set<String>> originalsAcls = convertAclToMap(allACLs);
 | |
|         Map<String, Set<String>> newAcls = convertAclToMap(acl);
 | |
| 
 | |
|         // iterate through the original ACEs
 | |
|         for (Map.Entry<String, Set<String>> ace : originalsAcls.entrySet())
 | |
|         {
 | |
| 
 | |
|             // add permissions
 | |
|             Set<String> addPermissions = newAcls.get(ace.getKey());
 | |
|             if (addPermissions != null)
 | |
|             {
 | |
|                 ace.getValue().addAll(addPermissions);
 | |
|             }
 | |
| 
 | |
|             // create new ACE
 | |
|             if (!ace.getValue().isEmpty())
 | |
|             {
 | |
|                 newAces.add(new AccessControlEntryImpl(new AccessControlPrincipalDataImpl(ace
 | |
|                         .getKey()), new ArrayList<String>(ace.getValue())));
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return new AccessControlListImpl(newAces);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets the given ACL.
 | |
|      */
 | |
|     public void applyACL(NodeRef nodeRef, TypeDefinitionWrapper type, Acl aces)
 | |
|     {
 | |
|         boolean hasAces = (aces != null) && (aces.getAces() != null) && !aces.getAces().isEmpty();
 | |
| 
 | |
|         if (!hasAces && !permissionService.getInheritParentPermissions(nodeRef))
 | |
|         {
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         if (!type.getTypeDefinition(false).isControllableAcl())
 | |
|         {
 | |
|             throw new CmisConstraintException("Object is not ACL controllable!");
 | |
|         }
 | |
| 
 | |
|         // remove all permissions
 | |
|         permissionService.deletePermissions(nodeRef);
 | |
| 
 | |
|         // set new permissions
 | |
|         for (Ace ace : aces.getAces())
 | |
|         {
 | |
|             String principalId = ace.getPrincipalId();
 | |
|             if (CMIS_USER.equals(principalId))
 | |
|             {
 | |
|                 principalId = AuthenticationUtil.getFullyAuthenticatedUser();
 | |
|             }
 | |
| 
 | |
|             List<String> permissions = translatePermissionsFromCMIS(ace.getPermissions());
 | |
|             for (String permission : permissions)
 | |
|             {
 | |
|                 permissionService.setPermission(nodeRef, principalId, permission, true);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     private List<String> translatePermissionsFromCMIS(List<String> permissions)
 | |
|     {
 | |
|         List<String> result = new ArrayList<String>();
 | |
| 
 | |
|         if (permissions == null)
 | |
|         {
 | |
|             return result;
 | |
|         }
 | |
| 
 | |
|         for (String permission : permissions)
 | |
|         {
 | |
|             if (permission == null)
 | |
|             {
 | |
|                 throw new CmisConstraintException("Invalid null permission!");
 | |
|             }
 | |
| 
 | |
|             if (BasicPermissions.READ.equals(permission))
 | |
|             {
 | |
|                 result.add(PermissionService.READ);
 | |
|             }
 | |
|             else if (BasicPermissions.WRITE.equals(permission))
 | |
|             {
 | |
|                 result.add(PermissionService.WRITE);
 | |
|             }
 | |
|             else if (BasicPermissions.ALL.equals(permission))
 | |
|             {
 | |
|                 result.add(PermissionService.ALL_PERMISSIONS);
 | |
|             }
 | |
|             else if (!permission.startsWith("{"))
 | |
|             {
 | |
|                 result.add(permission);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 int sepIndex = permission.lastIndexOf('.');
 | |
|                 if (sepIndex == -1)
 | |
|                 {
 | |
|                     result.add(permission);
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     result.add(permission.substring(sepIndex + 1));
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     public void applyPolicies(NodeRef nodeRef, TypeDefinitionWrapper type, List<String> policies)
 | |
|     {
 | |
|         if ((policies == null) || (policies.isEmpty()))
 | |
|         {
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         if (!type.getTypeDefinition(false).isControllablePolicy())
 | |
|         {
 | |
|             throw new CmisConstraintException("Object is not policy controllable!");
 | |
|         }
 | |
| 
 | |
|         // nothing else to do...
 | |
|     }
 | |
| 
 | |
|     @SuppressWarnings("unchecked")
 | |
| 	public ObjectList query(String statement, Boolean includeAllowableActions,
 | |
|             IncludeRelationships includeRelationships, String renditionFilter, BigInteger maxItems, BigInteger skipCount/*, CmisVersion cmisVersion*/)
 | |
|     {
 | |
|         // prepare results
 | |
|         ObjectListImpl result = new ObjectListImpl();
 | |
|         result.setObjects(new ArrayList<ObjectData>());
 | |
| 
 | |
|         // prepare query
 | |
|         CMISQueryOptions options = new CMISQueryOptions(statement, getRootStoreRef());
 | |
|         CmisVersion cmisVersion = getRequestCmisVersion();
 | |
|         options.setCmisVersion(cmisVersion);
 | |
|         options.setQueryMode(CMISQueryMode.CMS_WITH_ALFRESCO_EXTENSIONS);
 | |
| 
 | |
|         int skip = 0;
 | |
|         if ((skipCount != null) && (skipCount.intValue() >= 0))
 | |
|         {
 | |
|             skip = skipCount.intValue();
 | |
|             options.setSkipCount(skip);
 | |
|         }
 | |
| 
 | |
|         if ((maxItems != null) && (maxItems.intValue() >= 0))
 | |
|         {
 | |
|             options.setMaxItems(maxItems.intValue());
 | |
|         }
 | |
| 
 | |
|         boolean fetchObject = includeAllowableActions || (includeRelationships != IncludeRelationships.NONE)
 | |
|                 || (!RENDITION_NONE.equals(renditionFilter));
 | |
| 
 | |
|         // query
 | |
|         CMISResultSet rs = getOpenCMISQueryService().query(options);
 | |
|         try
 | |
|         {
 | |
|             CMISResultSetColumn[] columns = rs.getMetaData().getColumns();
 | |
| 
 | |
|             for (CMISResultSetRow row : rs)
 | |
|             {
 | |
|                 NodeRef nodeRef = row.getNodeRef();
 | |
|                 
 | |
|                 if(!nodeService.exists(nodeRef) || filter(nodeRef))
 | |
|                 {
 | |
|                     continue;
 | |
|                 }
 | |
|                 
 | |
|                 TypeDefinitionWrapper type = getType(nodeRef);
 | |
|                 if (type == null)
 | |
|                 {
 | |
|                     continue;
 | |
|                 }
 | |
|                 
 | |
|                 ObjectDataImpl hit = new ObjectDataImpl();
 | |
|                 PropertiesImpl properties = new PropertiesImpl();
 | |
|                 hit.setProperties(properties);
 | |
| 
 | |
|                 Map<String, Serializable> values = row.getValues();
 | |
| 
 | |
|                 for (CMISResultSetColumn column : columns)
 | |
|                 {
 | |
|                     AbstractPropertyData<?> property = getProperty(column.getCMISDataType(),
 | |
|                             column.getCMISPropertyDefinition(), values.get(column.getName()));
 | |
|                     property.setQueryName(column.getName());
 | |
|                     properties.addProperty(property);
 | |
|                 }
 | |
| 
 | |
|                 if (fetchObject)
 | |
|                 {
 | |
|                     // set allowable actions
 | |
|                     if (includeAllowableActions)
 | |
|                     {
 | |
|                         CMISNodeInfoImpl nodeInfo = createNodeInfo(nodeRef);
 | |
|                         if(!nodeInfo.getObjectVariant().equals(CMISObjectVariant.NOT_EXISTING))
 | |
|                         {
 | |
|                             hit.setAllowableActions(getAllowableActions(nodeInfo));
 | |
|                         }
 | |
|                     }
 | |
| 
 | |
|                     // set relationships
 | |
|                     if (includeRelationships != IncludeRelationships.NONE)
 | |
|                     {
 | |
|                         hit.setRelationships(getRelationships(nodeRef, includeRelationships/*, cmisVersion*/));
 | |
|                     }
 | |
| 
 | |
|                     // set renditions
 | |
|                     if (!RENDITION_NONE.equals(renditionFilter))
 | |
|                     {
 | |
|                         List<RenditionData> renditions = getRenditions(nodeRef, renditionFilter, null, null);
 | |
|                         if ((renditions != null) && (!renditions.isEmpty()))
 | |
|                         {
 | |
|                             hit.setRenditions(renditions);
 | |
|                         }
 | |
|                         else
 | |
|                         {
 | |
|                         	hit.setRenditions(Collections.EMPTY_LIST);
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 result.getObjects().add(hit);
 | |
|             }
 | |
| 
 | |
|             long numberFound = rs.getNumberFound();
 | |
|             if(numberFound != -1)
 | |
|             {
 | |
|             	result.setNumItems(BigInteger.valueOf(numberFound));
 | |
|             }
 | |
|             result.setHasMoreItems(rs.hasMore());
 | |
| 
 | |
|         } finally
 | |
|         {
 | |
|             rs.close();
 | |
|         }
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets property values.
 | |
|      */
 | |
|     @SuppressWarnings({ "rawtypes" })
 | |
|     public void setProperties(NodeRef nodeRef, TypeDefinitionWrapper type, Properties properties, String... exclude)
 | |
|     {
 | |
|         if (properties == null)
 | |
|         {
 | |
|             return;
 | |
|         }
 | |
|         
 | |
|         Map<String, PropertyData<?>> incomingPropsMap = properties.getProperties();
 | |
|         if (incomingPropsMap == null)
 | |
|         {
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         // extract property data into an easier to use form
 | |
|         Map<String, Pair<TypeDefinitionWrapper, Serializable>> propsMap = new HashMap<String, Pair<TypeDefinitionWrapper, Serializable>>();
 | |
|         for (String propertyId : incomingPropsMap.keySet())
 | |
|         {
 | |
|             PropertyData<?> property = incomingPropsMap.get(propertyId);
 | |
|             PropertyDefinitionWrapper propDef = type.getPropertyById(property.getId());
 | |
|             if (propDef == null)
 | |
|             {
 | |
|                 propDef = getOpenCMISDictionaryService().findProperty(propertyId);
 | |
|                 if (propDef == null)
 | |
|                 {
 | |
|                     throw new CmisInvalidArgumentException("Property " + property.getId() + " is unknown!");
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             Updatability updatability = propDef.getPropertyDefinition().getUpdatability();
 | |
|             if ((updatability == Updatability.READONLY)
 | |
|                     || (updatability == Updatability.WHENCHECKEDOUT && !checkOutCheckInService.isWorkingCopy(nodeRef)))
 | |
|             {
 | |
|                 throw new CmisInvalidArgumentException("Property " + property.getId() + " is read-only!");
 | |
|             }
 | |
|             TypeDefinitionWrapper propType = propDef.getOwningType();
 | |
|             Serializable value = getValue(property, propDef.getPropertyDefinition().getCardinality() == Cardinality.MULTI);
 | |
|             Pair<TypeDefinitionWrapper, Serializable> pair = new Pair<TypeDefinitionWrapper, Serializable>(propType, value);
 | |
|             propsMap.put(propertyId, pair);
 | |
|         }
 | |
| 
 | |
|         // Need to do deal with secondary types first
 | |
|         Pair<TypeDefinitionWrapper, Serializable> pair = propsMap.get(PropertyIds.SECONDARY_OBJECT_TYPE_IDS);
 | |
|         Serializable secondaryTypesProperty = (pair != null ? pair.getSecond() : null);
 | |
|         if(secondaryTypesProperty != null)
 | |
|         {
 | |
|             if (!(secondaryTypesProperty instanceof List))
 | |
|             {
 | |
|                 throw new CmisInvalidArgumentException("Secondary types must be a list!");
 | |
|             }
 | |
|             List secondaryTypes = (List)secondaryTypesProperty;
 | |
|             if(secondaryTypes != null && secondaryTypes.size() > 0)
 | |
|             {
 | |
|                 // add/remove secondary types/aspects
 | |
|                 processSecondaryTypes(nodeRef, secondaryTypes, propsMap);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         for (String propertyId : propsMap.keySet())
 | |
|         {
 | |
|             if(propertyId.equals(PropertyIds.SECONDARY_OBJECT_TYPE_IDS))
 | |
|             {
 | |
|                 // already handled above
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             pair = propsMap.get(propertyId);
 | |
|             TypeDefinitionWrapper propType = pair.getFirst();
 | |
|             Serializable value = pair.getSecond();
 | |
|             if (Arrays.binarySearch(exclude, propertyId) < 0)
 | |
|             {
 | |
|                 setProperty(nodeRef, propType, propertyId, value);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         List<CmisExtensionElement> extensions = properties.getExtensions();
 | |
|         if (extensions != null)
 | |
|         {
 | |
|         	boolean isNameChanging = properties.getProperties().containsKey(PropertyIds.NAME);
 | |
| 
 | |
|             for (CmisExtensionElement extension : extensions)
 | |
|             {
 | |
|                 if (ALFRESCO_EXTENSION_NAMESPACE.equals(extension.getNamespace())
 | |
|                         && SET_ASPECTS.equals(extension.getName()))
 | |
|                 {
 | |
|                     setAspectProperties(nodeRef, isNameChanging, extension);
 | |
|                     break;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @SuppressWarnings("rawtypes")
 | |
|     private void processSecondaryTypes(NodeRef nodeRef, List secondaryTypes, Map<String, Pair<TypeDefinitionWrapper, Serializable>> propsToAdd)
 | |
|     {
 | |
|         // diff existing aspects and secondaryTypes/aspects list
 | |
|         Set<QName> existingAspects = nodeService.getAspects(nodeRef);
 | |
|         Set<QName> secondaryTypeAspects = new HashSet<QName>();
 | |
|         for(Object o : secondaryTypes)
 | |
|         {
 | |
|             String secondaryType = (String)o;
 | |
|             
 | |
|             TypeDefinitionWrapper wrapper = getOpenCMISDictionaryService().findType(secondaryType);
 | |
|             if(wrapper != null)
 | |
|             {
 | |
|                 QName aspectQName = wrapper.getAlfrescoName();
 | |
|                 secondaryTypeAspects.add(aspectQName);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 throw new CmisInvalidArgumentException("Invalid secondary type id " + secondaryType);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         Set<QName> ignore = new HashSet<QName>();
 | |
|         ignore.add(ContentModel.ASPECT_REFERENCEABLE);
 | |
|         ignore.add(ContentModel.ASPECT_LOCALIZED);
 | |
| 
 | |
|         // aspects to add == the list of secondary types - existing aspects - ignored aspects
 | |
|         Set<QName> toAdd = new HashSet<QName>(secondaryTypeAspects);
 | |
|         toAdd.removeAll(existingAspects);
 | |
|         toAdd.removeAll(ignore);
 | |
| 
 | |
|         // aspects to remove == existing aspects - secondary types
 | |
|         Set<QName> aspectsToRemove = new HashSet<QName>();
 | |
|         aspectsToRemove.addAll(existingAspects);
 | |
|         aspectsToRemove.removeAll(ignore);
 | |
|         Iterator<QName> it = aspectsToRemove.iterator();
 | |
|         while(it.hasNext())
 | |
|         {
 | |
|             QName aspectQName = it.next();
 | |
|             TypeDefinitionWrapper w = getOpenCMISDictionaryService().findNodeType(aspectQName);
 | |
|             if(w == null || secondaryTypeAspects.contains(aspectQName))
 | |
|             {
 | |
|                 // the type is not exposed or is in the secondary types to set, so remove it from the to remove set
 | |
|                 it.remove();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // first, remove aspects
 | |
|         for(QName aspectQName : aspectsToRemove)
 | |
|         {
 | |
|             nodeService.removeAspect(nodeRef, aspectQName);
 | |
|             // aspect is being removed so remove all of its properties from the propsToAdd map
 | |
|             TypeDefinitionWrapper w = getOpenCMISDictionaryService().findNodeType(aspectQName);
 | |
|             for(PropertyDefinitionWrapper wr : w.getProperties())
 | |
|             {
 | |
|                 String propertyId = wr.getPropertyId();
 | |
|                 propsToAdd.remove(propertyId);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // add aspects and properties
 | |
|         for(QName aspectQName : toAdd)
 | |
|         {
 | |
|             nodeService.addAspect(nodeRef, aspectQName, null);
 | |
|             
 | |
|             // get aspect properties
 | |
|             AspectDefinition aspectDef = dictionaryService.getAspect(aspectQName);
 | |
|             Map<QName, org.alfresco.service.cmr.dictionary.PropertyDefinition> aspectPropDefs = aspectDef.getProperties();
 | |
|             TypeDefinitionWrapper w = getOpenCMISDictionaryService().findNodeType(aspectQName);
 | |
|             // for each aspect property...
 | |
|             for(QName propQName : aspectPropDefs.keySet())
 | |
|             {
 | |
|                 // find CMIS property id
 | |
|                 PropertyDefinitionWrapper property = w.getPropertyByQName(propQName);
 | |
|                 String propertyId = property.getPropertyId();
 | |
|                 if(!propsToAdd.containsKey(propertyId))
 | |
|                 {
 | |
|                     TypeDefinitionWrapper propType = property.getOwningType();
 | |
|                     // CMIS 1.1 secondary types specification requires that all secondary type properties are set
 | |
|                     // property not included in propsToAdd, add it with null value
 | |
|                     Pair<TypeDefinitionWrapper, Serializable> pair = new Pair<TypeDefinitionWrapper, Serializable>(propType, null);
 | |
|                     propsToAdd.put(propertyId, pair);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     public void addSecondaryTypes(NodeRef nodeRef, List<String> secondaryTypes)
 | |
|     {
 | |
|     	if(secondaryTypes != null && secondaryTypes.size() > 0)
 | |
|     	{
 | |
| 	    	for(String secondaryType : secondaryTypes)
 | |
| 	    	{
 | |
| 	            TypeDefinitionWrapper type = getType(secondaryType);
 | |
| 	            if (type == null)
 | |
| 	            {
 | |
| 	                throw new CmisInvalidArgumentException("Invalid secondaryType: " + secondaryType);
 | |
| 	            }
 | |
| 	    		nodeService.addAspect(nodeRef, type.getAlfrescoName(), null);
 | |
| 	    	}
 | |
|     	}
 | |
|     }
 | |
|     
 | |
|     public void removeSecondaryTypes(NodeRef nodeRef, List<String> secondaryTypes)
 | |
|     {
 | |
|     	if(secondaryTypes != null && secondaryTypes.size() > 0)
 | |
|     	{
 | |
| 	    	for(String secondaryType : secondaryTypes)
 | |
| 	    	{
 | |
| 	            TypeDefinitionWrapper type = getType(secondaryType);
 | |
| 	            if (type == null)
 | |
| 	            {
 | |
| 	                throw new CmisInvalidArgumentException("Invalid secondaryType: " + secondaryType);
 | |
| 	            }
 | |
| 	    		nodeService.removeAspect(nodeRef, type.getAlfrescoName());
 | |
| 	    	}
 | |
|     	}
 | |
|     }
 | |
| 
 | |
|     private void setAspectProperties(NodeRef nodeRef, boolean isNameChanging, CmisExtensionElement aspectExtension)
 | |
|     {
 | |
|         if (aspectExtension.getChildren() == null)
 | |
|         {
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         List<String> aspectsToAdd = new ArrayList<String>();
 | |
|         List<String> aspectsToRemove = new ArrayList<String>();
 | |
|         Map<QName, List<Serializable>> aspectProperties = new HashMap<QName, List<Serializable>>();
 | |
| 
 | |
|         for (CmisExtensionElement extension : aspectExtension.getChildren())
 | |
|         {
 | |
|             if (!ALFRESCO_EXTENSION_NAMESPACE.equals(extension.getNamespace()))
 | |
|             {
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             if (ASPECTS_TO_ADD.equals(extension.getName()) && (extension.getValue() != null))
 | |
|             {
 | |
|                 aspectsToAdd.add(extension.getValue());
 | |
|             }
 | |
|             else if (ASPECTS_TO_REMOVE.equals(extension.getName()) && (extension.getValue() != null))
 | |
|             {
 | |
|                 aspectsToRemove.add(extension.getValue());
 | |
|             }
 | |
|             else if (PROPERTIES.equals(extension.getName()) && (extension.getChildren() != null))
 | |
|             {
 | |
|                 for (CmisExtensionElement property : extension.getChildren())
 | |
|                 {
 | |
|                     if (!property.getName().startsWith("property"))
 | |
|                     {
 | |
|                         continue;
 | |
|                     }
 | |
| 
 | |
|                     String propertyId = (property.getAttributes() == null ? null : property.getAttributes().get(
 | |
|                             "propertyDefinitionId"));
 | |
|                     if ((propertyId == null) || (property.getChildren() == null))
 | |
|                     {
 | |
|                         continue;
 | |
|                     }
 | |
| 
 | |
|                     PropertyType propertyType = PropertyType.STRING;
 | |
|                     DatatypeFactory df = null;
 | |
|                     if (property.getName().equals("propertyBoolean"))
 | |
|                     {
 | |
|                         propertyType = PropertyType.BOOLEAN;
 | |
|                     }
 | |
|                     else if (property.getName().equals("propertyInteger"))
 | |
|                     {
 | |
|                         propertyType = PropertyType.INTEGER;
 | |
|                     }
 | |
|                     else if (property.getName().equals("propertyDateTime"))
 | |
|                     {
 | |
|                         propertyType = PropertyType.DATETIME;
 | |
|                         try
 | |
|                         {
 | |
|                             df = DatatypeFactory.newInstance();
 | |
|                         }
 | |
|                         catch (DatatypeConfigurationException e)
 | |
|                         {
 | |
|                             throw new CmisRuntimeException("Aspect conversation exception: " + e.getMessage(), e);
 | |
|                         }
 | |
|                     }
 | |
|                     else if (property.getName().equals("propertyDecimal"))
 | |
|                     {
 | |
|                         propertyType = PropertyType.DECIMAL;
 | |
|                     }
 | |
| 
 | |
|                     ArrayList<Serializable> values = new ArrayList<Serializable>();
 | |
|                     if (property.getChildren() != null)
 | |
|                     {
 | |
| //                        try
 | |
| //                        {
 | |
|                             for (CmisExtensionElement valueElement : property.getChildren())
 | |
|                             {
 | |
|                                 if ("value".equals(valueElement.getName()))
 | |
|                                 {
 | |
|                                     switch (propertyType)
 | |
|                                     {
 | |
|                                     case BOOLEAN:
 | |
|                                     	try
 | |
|                                     	{
 | |
|                                     		values.add(Boolean.parseBoolean(valueElement.getValue()));
 | |
| 	                                	}
 | |
| 	                                	catch (Exception e)
 | |
| 	                                	{
 | |
| 	                                		throw new CmisInvalidArgumentException("Invalid property aspect value: " + propertyId, e);
 | |
| 	                                	}
 | |
|                                         break;
 | |
|                                     case DATETIME:
 | |
|                                     	try
 | |
|                                     	{
 | |
| 	                                        values.add(df.newXMLGregorianCalendar(valueElement.getValue())
 | |
| 	                                                .toGregorianCalendar());
 | |
|                                     	}
 | |
|                                     	catch (Exception e)
 | |
|                                     	{
 | |
|                                     		throw new CmisInvalidArgumentException("Invalid property aspect value: " + propertyId, e);
 | |
|                                     	}
 | |
|                                         break;
 | |
|                                     case INTEGER:
 | |
|                                     	BigInteger value = null;
 | |
|                                     	try
 | |
|                                     	{
 | |
|                                     		value = new BigInteger(valueElement.getValue());
 | |
|                                     	}
 | |
|                                     	catch (Exception e)
 | |
|                                     	{
 | |
|                                     		throw new CmisInvalidArgumentException("Invalid property aspect value: " + propertyId, e);
 | |
|                                     	}
 | |
| 
 | |
|                                     	// overflow check
 | |
|                                     	PropertyDefinitionWrapper propDef = getOpenCMISDictionaryService().findProperty(propertyId);
 | |
|                                         if(propDef == null)
 | |
|                                         {
 | |
|                                             throw new CmisInvalidArgumentException("Property " + propertyId + " is unknown!");
 | |
|                                         }
 | |
|                                         
 | |
|                                         QName propertyQName = propDef.getPropertyAccessor().getMappedProperty();
 | |
|                                         if (propertyQName == null)
 | |
|                                         {
 | |
|                                             throw new CmisConstraintException("Unable to set property " + propertyId + "!");
 | |
|                                         }
 | |
| 
 | |
|                                 		org.alfresco.service.cmr.dictionary.PropertyDefinition def = dictionaryService.getProperty(propertyQName);
 | |
|                                 		QName dataDef = def.getDataType().getName();
 | |
| 
 | |
|                                 		if (dataDef.equals(DataTypeDefinition.INT) && (value.compareTo(maxInt) > 0 || value.compareTo(minInt) < 0))
 | |
|                                 		{
 | |
|                                 			throw new CmisConstraintException("Value is out of range for property " + propertyId);
 | |
|                                 		}
 | |
| 
 | |
|                                 		if (dataDef.equals(DataTypeDefinition.LONG) && (value.compareTo(maxLong) > 0 || value.compareTo(minLong) < 0 ))
 | |
|                                 		{
 | |
|                                 			throw new CmisConstraintException("Value is out of range for property " + propertyId);
 | |
|                                 		}
 | |
|                                     	
 | |
|                                         values.add(value);
 | |
|                                         break;
 | |
|                                     case DECIMAL:
 | |
|                                     	try
 | |
|                                     	{
 | |
|                                     		values.add(new BigDecimal(valueElement.getValue()));
 | |
|                                     	}
 | |
|                                     	catch (Exception e)
 | |
|                                     	{
 | |
|                                     		throw new CmisInvalidArgumentException("Invalid property aspect value: " + propertyId, e);
 | |
|                                     	}
 | |
|                                         break;
 | |
|                                     default:
 | |
|                                         values.add(valueElement.getValue());
 | |
|                                     }
 | |
|                                 }
 | |
|                             }
 | |
|                     }
 | |
| 
 | |
|                     aspectProperties.put(QName.createQName(propertyId, namespaceService), values);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // remove and add aspects
 | |
|         String aspectType = null;
 | |
|         try
 | |
|         {
 | |
|             for (String aspect : aspectsToRemove)
 | |
|             {
 | |
|                 aspectType = aspect;
 | |
| 
 | |
|                 TypeDefinitionWrapper type = getType(aspect);
 | |
|                 if (type == null)
 | |
|                 {
 | |
|                     throw new CmisInvalidArgumentException("Invalid aspect: " + aspectType);
 | |
|                 }
 | |
| 
 | |
|                 QName typeName = type.getAlfrescoName();
 | |
|                 // if aspect is hidden aspect, remove only if hidden node is not client controlled
 | |
|                 if(typeName.equals(ContentModel.ASPECT_HIDDEN))
 | |
|                 {
 | |
|                 	if(hiddenAspect.isClientControlled(nodeRef) || aspectProperties.containsKey(ContentModel.PROP_CLIENT_CONTROLLED))
 | |
|                 	{
 | |
|                 		// manipulate hidden aspect only if client controlled
 | |
|                 		nodeService.removeAspect(nodeRef, typeName);	
 | |
|                 	}
 | |
|                 	
 | |
|                 	
 | |
|                 	
 | |
| //                	if(!isNameChanging && !hiddenAspect.isClientControlled(nodeRef) && !aspectProperties.containsKey(ContentModel.PROP_CLIENT_CONTROLLED))
 | |
| //                	{
 | |
| //                    	nodeService.removeAspect(nodeRef, typeName);	
 | |
| //                	}
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                 	nodeService.removeAspect(nodeRef, typeName);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             for (String aspect : aspectsToAdd)
 | |
|             {
 | |
|                 aspectType = aspect;
 | |
| 
 | |
|                 TypeDefinitionWrapper type = getType(aspect);
 | |
|                 if (type == null)
 | |
|                 {
 | |
|                     throw new CmisInvalidArgumentException("Invalid aspect: " + aspectType);
 | |
|                 }
 | |
| 
 | |
|                 QName typeName = type.getAlfrescoName();
 | |
|                 // if aspect is hidden aspect, remove only if hidden node is not client controlled
 | |
|                 if(typeName.equals(ContentModel.ASPECT_HIDDEN))
 | |
|                 {
 | |
|                 	if(hiddenAspect.isClientControlled(nodeRef) || aspectProperties.containsKey(ContentModel.PROP_CLIENT_CONTROLLED))
 | |
|                 	{
 | |
|                 		// manipulate hidden aspect only if client controlled
 | |
|                 		nodeService.addAspect(nodeRef, type.getAlfrescoName(),
 | |
|     	                        Collections.<QName, Serializable> emptyMap());	
 | |
|                 	}
 | |
|                 	
 | |
| //                	if(!isNameChanging && !hiddenAspect.isClientControlled(nodeRef) && !aspectProperties.containsKey(ContentModel.PROP_CLIENT_CONTROLLED))
 | |
| //                	{
 | |
| //                		nodeService.addAspect(nodeRef, type.getAlfrescoName(),
 | |
| //    	                        Collections.<QName, Serializable> emptyMap());	
 | |
| //                	}
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                 	nodeService.addAspect(nodeRef, type.getAlfrescoName(),
 | |
| 	                        Collections.<QName, Serializable> emptyMap());
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         catch (InvalidAspectException e)
 | |
|         {
 | |
|             throw new CmisInvalidArgumentException("Invalid aspect: " + aspectType);
 | |
|         }
 | |
|         catch (InvalidNodeRefException e)
 | |
|         {
 | |
|             throw new CmisInvalidArgumentException("Invalid node: " + nodeRef);
 | |
|         }
 | |
| 
 | |
|         // set property
 | |
|         for (Map.Entry<QName, List<Serializable>> property : aspectProperties.entrySet())
 | |
|         {
 | |
|         	QName propertyQName = property.getKey();
 | |
| 
 | |
|             if (property.getValue().isEmpty())
 | |
|             {
 | |
|                 if(HiddenAspect.HIDDEN_PROPERTIES.contains(property.getKey()))
 | |
|                 {
 | |
|                 	if(hiddenAspect.isClientControlled(nodeRef) || aspectProperties.containsKey(ContentModel.PROP_CLIENT_CONTROLLED))
 | |
|                 	{
 | |
|                 		// manipulate hidden aspect property only if client controlled
 | |
|                         nodeService.removeProperty(nodeRef, propertyQName);
 | |
|                 	}
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                 	nodeService.removeProperty(nodeRef, property.getKey());	
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if(HiddenAspect.HIDDEN_PROPERTIES.contains(property.getKey()))
 | |
|                 {
 | |
|                 	if(hiddenAspect.isClientControlled(nodeRef) || aspectProperties.containsKey(ContentModel.PROP_CLIENT_CONTROLLED))
 | |
|                 	{
 | |
|                 		// manipulate hidden aspect property only if client controlled
 | |
|                     	nodeService.setProperty(nodeRef, property.getKey(), property.getValue().size() == 1 ? property
 | |
|                     			.getValue().get(0) : (Serializable) property.getValue());
 | |
|                 	}
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|             	Serializable value = (Serializable)property.getValue();
 | |
|                 	nodeService.setProperty(nodeRef, property.getKey(), property.getValue().size() == 1 ? property
 | |
|                         .getValue().get(0) : value);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets a property value.
 | |
|      */
 | |
| 	public void setProperty(NodeRef nodeRef, TypeDefinitionWrapper type, String propertyId, Serializable value)
 | |
|     {
 | |
|         if (propertyId == null)
 | |
|         {
 | |
|             throw new CmisInvalidArgumentException("Cannot process not null property!");
 | |
|         }
 | |
| 
 | |
|         PropertyDefinitionWrapper propDef = type.getPropertyById(propertyId);
 | |
|         if (propDef == null)
 | |
|         {
 | |
|             throw new CmisInvalidArgumentException("Property " + propertyId + " is unknown!");
 | |
|         }
 | |
| 
 | |
|         Updatability updatability = propDef.getPropertyDefinition().getUpdatability();
 | |
|         if ((updatability == Updatability.READONLY)
 | |
|                 || (updatability == Updatability.WHENCHECKEDOUT && !checkOutCheckInService.isWorkingCopy(nodeRef)))
 | |
|         {
 | |
|             throw new CmisInvalidArgumentException("Property " + propertyId + " is read-only!");
 | |
|         }
 | |
| 
 | |
|         if(propDef.getPropertyId().equals(PropertyIds.SECONDARY_OBJECT_TYPE_IDS))
 | |
|         {
 | |
|             throw new IllegalArgumentException("Cannot process " + PropertyIds.SECONDARY_OBJECT_TYPE_IDS + " in setProperty");
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|         	QName propertyQName = propDef.getPropertyAccessor().getMappedProperty();
 | |
|         	if (propertyQName == null)
 | |
|         	{
 | |
|         		throw new CmisConstraintException("Unable to set property " + propertyId + "!");
 | |
|         	}
 | |
|         
 | |
|         	if (propertyId.equals(PropertyIds.NAME))
 | |
|         	{
 | |
|         		if (!(value instanceof String))
 | |
|         		{
 | |
|         			throw new CmisInvalidArgumentException("Object name must be a string!");
 | |
|         		}
 | |
| 
 | |
|         		try
 | |
|         		{
 | |
|         			fileFolderService.rename(nodeRef, value.toString());
 | |
|         		}
 | |
|         		catch (FileExistsException e)
 | |
|         		{
 | |
|         			throw new CmisContentAlreadyExistsException("An object with this name already exists!", e);
 | |
|         		}
 | |
|         		catch (FileNotFoundException e)
 | |
|         		{
 | |
|         			throw new CmisInvalidArgumentException("Object with id " + nodeRef.getId() + " not found!");
 | |
|         		}
 | |
|         	}
 | |
|         	else
 | |
|             {
 | |
|                 // overflow check
 | |
|                 if (propDef.getPropertyDefinition().getPropertyType() == PropertyType.INTEGER && value instanceof BigInteger)
 | |
|                 {
 | |
|                     org.alfresco.service.cmr.dictionary.PropertyDefinition def = dictionaryService.getProperty(propertyQName);
 | |
|                     QName dataDef = def.getDataType().getName();
 | |
|                     BigInteger bigValue = (BigInteger) value;
 | |
| 
 | |
|                     if ((bigValue.compareTo(maxInt) > 0 || bigValue.compareTo(minInt) < 0) && dataDef.equals(DataTypeDefinition.INT))
 | |
|                     {
 | |
|                         throw new CmisConstraintException("Value is out of range for property " + propertyQName.getLocalName());
 | |
|                     }
 | |
| 
 | |
|                     if ((bigValue.compareTo(maxLong) > 0 || bigValue.compareTo(minLong) < 0) && dataDef.equals(DataTypeDefinition.LONG))
 | |
|                     {
 | |
|                         throw new CmisConstraintException("Value is out of range for property " + propertyQName.getLocalName());
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 nodeService.setProperty(nodeRef, propertyQName, value);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     private Serializable getValue(PropertyData<?> property, boolean isMultiValue)
 | |
|     {
 | |
|         if ((property.getValues() == null) || (property.getValues().isEmpty()))
 | |
|         {
 | |
|             return null;
 | |
|         }
 | |
| 
 | |
|         if (isMultiValue)
 | |
|         {
 | |
|             return (Serializable) property.getValues();
 | |
|         }
 | |
| 
 | |
|         return (Serializable) property.getValues().get(0);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns content changes.
 | |
|      */
 | |
|     public ObjectList getContentChanges(Holder<String> changeLogToken, BigInteger maxItems)
 | |
|     {
 | |
|         final ObjectListImpl result = new ObjectListImpl();
 | |
|         result.setObjects(new ArrayList<ObjectData>());
 | |
| 
 | |
|         EntryIdCallback changeLogCollectingCallback = new EntryIdCallback(true)
 | |
|         {
 | |
|             @Override
 | |
|             public boolean handleAuditEntry(Long entryId, String user, long time, Map<String, Serializable> values)
 | |
|             {
 | |
|                 result.getObjects().addAll(createChangeEvents(time, values));
 | |
|                 return super.handleAuditEntry(entryId, user, time, values);
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         Long from = null;
 | |
|         if ((changeLogToken != null) && (changeLogToken.getValue() != null))
 | |
|         {
 | |
|             try
 | |
|             {
 | |
|                 from = Long.parseLong(changeLogToken.getValue());
 | |
|             }
 | |
|             catch (NumberFormatException e)
 | |
|             {
 | |
|                 throw new CmisInvalidArgumentException("Invalid change log token: " + changeLogToken);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         AuditQueryParameters params = new AuditQueryParameters();
 | |
|         params.setApplicationName(CMIS_CHANGELOG_AUDIT_APPLICATION);
 | |
|         params.setForward(true);
 | |
|         params.setFromId(from);
 | |
| 
 | |
|         int maxResults = (maxItems == null ? 0 : maxItems.intValue());
 | |
|         maxResults = (maxResults < 1 ? 0 : maxResults + 1);
 | |
| 
 | |
|         auditService.auditQuery(changeLogCollectingCallback, params, maxResults);
 | |
| 
 | |
|         String newChangeLogToken = null;
 | |
|         if (maxResults > 0)
 | |
|         {
 | |
|             if (result.getObjects().size() >= maxResults)
 | |
|             {
 | |
|             	StringBuilder clt = new StringBuilder();
 | |
|                 newChangeLogToken = (from == null ? clt.append(maxItems.intValue() + 1).toString() : clt.append(from.longValue() + maxItems.intValue()).toString());
 | |
|                 result.getObjects().remove(result.getObjects().size() - 1).getId();
 | |
|                 result.setHasMoreItems(true);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 result.setHasMoreItems(false);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if (changeLogToken != null)
 | |
|         {
 | |
|             changeLogToken.setValue(newChangeLogToken);
 | |
|         }
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     @SuppressWarnings("unchecked")
 | |
|     private List<ObjectData> createChangeEvents(long time, Map<String, Serializable> values)
 | |
|     {
 | |
|         List<ObjectData> result = new ArrayList<ObjectData>();
 | |
| 
 | |
|         if ((values == null) || (values.size() == 0))
 | |
|         {
 | |
|             return result;
 | |
|         }
 | |
| 
 | |
|         GregorianCalendar changeTime = new GregorianCalendar();
 | |
|         changeTime.setTimeInMillis(time);
 | |
| 
 | |
|         String appPath = "/" + CMIS_CHANGELOG_AUDIT_APPLICATION + "/";
 | |
| 
 | |
|         for (Entry<String, Serializable> entry : values.entrySet())
 | |
|         {
 | |
|             if ((entry.getKey() == null) || (!(entry.getValue() instanceof Map)))
 | |
|             {
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             String path = entry.getKey();
 | |
|             if (!path.startsWith(appPath))
 | |
|             {
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             ChangeType changeType = null;
 | |
|             String changePath = path.substring(appPath.length()).toLowerCase();
 | |
|             for (ChangeType c : ChangeType.values())
 | |
|             {
 | |
|                 if (changePath.startsWith(c.value().toLowerCase()))
 | |
|                 {
 | |
|                     changeType = c;
 | |
|                     break;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (changeType == null)
 | |
|             {
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             Map<String, Serializable> valueMap = (Map<String, Serializable>) entry.getValue();
 | |
|             String objectId = (String) valueMap.get(CMISChangeLogDataExtractor.KEY_OBJECT_ID);
 | |
| 
 | |
|             // build object
 | |
|             ObjectDataImpl object = new ObjectDataImpl();
 | |
|             result.add(object);
 | |
| 
 | |
|             PropertiesImpl properties = new PropertiesImpl();
 | |
|             object.setProperties(properties);
 | |
|             PropertyIdImpl objectIdProperty = new PropertyIdImpl(PropertyIds.OBJECT_ID, objectId);
 | |
|             properties.addProperty(objectIdProperty);
 | |
| 
 | |
|             ChangeEventInfoDataImpl changeEvent = new ChangeEventInfoDataImpl();
 | |
|             object.setChangeEventInfo(changeEvent);
 | |
|             changeEvent.setChangeType(changeType);
 | |
|             changeEvent.setChangeTime(changeTime);
 | |
|         }
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     private class EntryIdCallback implements AuditQueryCallback
 | |
|     {
 | |
|         private final boolean valuesRequired;
 | |
|         private Long entryId;
 | |
| 
 | |
|         public EntryIdCallback(boolean valuesRequired)
 | |
|         {
 | |
|             this.valuesRequired = valuesRequired;
 | |
|         }
 | |
| 
 | |
|         public String getEntryId()
 | |
|         {
 | |
|             return entryId == null ? null : entryId.toString();
 | |
|         }
 | |
| 
 | |
|         public boolean valuesRequired()
 | |
|         {
 | |
|             return this.valuesRequired;
 | |
|         }
 | |
| 
 | |
|         public final boolean handleAuditEntry(Long entryId, String applicationName, String user, long time,
 | |
|                 Map<String, Serializable> values)
 | |
|         {
 | |
|             if (applicationName.equals(CMIS_CHANGELOG_AUDIT_APPLICATION))
 | |
|             {
 | |
|                 return handleAuditEntry(entryId, user, time, values);
 | |
|             }
 | |
|             return true;
 | |
|         }
 | |
| 
 | |
|         public boolean handleAuditEntry(Long entryId, String user, long time, Map<String, Serializable> values)
 | |
|         {
 | |
|             this.entryId = entryId;
 | |
|             return true;
 | |
|         }
 | |
| 
 | |
|         public boolean handleAuditEntryError(Long entryId, String errorMsg, Throwable error)
 | |
|         {
 | |
|             throw new CmisRuntimeException("Audit entry " + entryId + ": " + errorMsg, error);
 | |
|         }
 | |
|     };
 | |
| 
 | |
|     // --------------------------------------------------------------
 | |
|     // OpenCMIS methods
 | |
|     // --------------------------------------------------------------
 | |
| 
 | |
|     /**
 | |
|      * Returns the value of the given property if it exists and is of the
 | |
|      * correct type.
 | |
|      */
 | |
|     public String getStringProperty(Properties properties, String propertyId)
 | |
|     {
 | |
|         if ((properties == null) || (properties.getProperties() == null))
 | |
|         {
 | |
|             return null;
 | |
|         }
 | |
| 
 | |
|         PropertyData<?> property = properties.getProperties().get(propertyId);
 | |
|         if (!(property instanceof PropertyString))
 | |
|         {
 | |
|             return null;
 | |
|         }
 | |
| 
 | |
|         return ((PropertyString) property).getFirstValue();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns the value of the given property if it exists and is of the
 | |
|      * correct type.
 | |
|      */
 | |
|     public String getIdProperty(Properties properties, String propertyId)
 | |
|     {
 | |
|         if ((properties == null) || (properties.getProperties() == null))
 | |
|         {
 | |
|             return null;
 | |
|         }
 | |
| 
 | |
|         PropertyData<?> property = properties.getProperties().get(propertyId);
 | |
|         if (!(property instanceof PropertyId))
 | |
|         {
 | |
|             return null;
 | |
|         }
 | |
| 
 | |
|         return ((PropertyId) property).getFirstValue();
 | |
|     }
 | |
| 
 | |
|     public String getNameProperty(Properties properties, String fallback)
 | |
|     {
 | |
|         String name = getStringProperty(properties, PropertyIds.NAME);
 | |
|         if ((name == null) || (name.trim().length() == 0))
 | |
|         {
 | |
|             if (fallback == null)
 | |
|             {
 | |
|                 throw new CmisInvalidArgumentException("Property " + PropertyIds.NAME + " must be set!");
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 name = fallback;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return name;
 | |
|     }
 | |
| 
 | |
|     public String getObjectTypeIdProperty(Properties properties)
 | |
|     {
 | |
|         String objectTypeId = getIdProperty(properties, PropertyIds.OBJECT_TYPE_ID);
 | |
|         if ((objectTypeId == null) || (objectTypeId.trim().length() == 0))
 | |
|         {
 | |
|             throw new CmisInvalidArgumentException("Property " + PropertyIds.OBJECT_TYPE_ID + " must be set!");
 | |
|         }
 | |
| 
 | |
|         return objectTypeId;
 | |
|     }
 | |
| 
 | |
|     public String getSourceIdProperty(Properties properties)
 | |
|     {
 | |
|         String id = getIdProperty(properties, PropertyIds.SOURCE_ID);
 | |
|         if ((id == null) || (id.trim().length() == 0))
 | |
|         {
 | |
|             throw new CmisInvalidArgumentException("Property " + PropertyIds.SOURCE_ID + " must be set!");
 | |
|         }
 | |
| 
 | |
|         return id;
 | |
|     }
 | |
| 
 | |
|     public String getTargetIdProperty(Properties properties)
 | |
|     {
 | |
|         String id = getIdProperty(properties, PropertyIds.TARGET_ID);
 | |
|         if ((id == null) || (id.trim().length() == 0))
 | |
|         {
 | |
|             throw new CmisInvalidArgumentException("Property " + PropertyIds.TARGET_ID + " must be set!");
 | |
|         }
 | |
| 
 | |
|         return id;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns the repository info object.
 | |
|      */
 | |
|     public RepositoryInfo getRepositoryInfo(CmisVersion cmisVersion)
 | |
|     {
 | |
|         return createRepositoryInfo(cmisVersion);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns the repository id.
 | |
|      */
 | |
|     public String getRepositoryId()
 | |
|     {
 | |
|         return descriptorService.getCurrentRepositoryDescriptor().getId();
 | |
|     }
 | |
| 
 | |
|     public PagingResults<FileInfo> getChildren(NodeRef folderNodeRef, Set<QName> typeqnames, List<Pair<QName, Boolean>> sortProps, PagingRequest pageRequest)
 | |
|     {
 | |
|         return fileFolderService.list(folderNodeRef, typeqnames, ignoreChildrenQNames, sortProps, pageRequest);
 | |
|     }
 | |
|     public PagingResults<FileInfo> getChildren(NodeRef folderNodeRef, List<Pair<QName, Boolean>> sortProps, PagingRequest pageRequest)
 | |
|     {
 | |
|         return fileFolderService.list(folderNodeRef, true, true, ignoreChildrenQNames, sortProps, pageRequest);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Creates the repository info object.
 | |
|      */
 | |
|     private RepositoryInfo createRepositoryInfo(CmisVersion cmisVersion)
 | |
|     {
 | |
|         Descriptor currentDescriptor = descriptorService.getCurrentRepositoryDescriptor();
 | |
| 
 | |
|         // get change token
 | |
|         boolean auditEnabled = auditService.isAuditEnabled(CMIS_CHANGELOG_AUDIT_APPLICATION, "/"
 | |
|                 + CMIS_CHANGELOG_AUDIT_APPLICATION);
 | |
|         String latestChangeLogToken = null;
 | |
| 
 | |
|         if (auditEnabled)
 | |
|         {
 | |
|             EntryIdCallback auditQueryCallback = new EntryIdCallback(false);
 | |
|             AuditQueryParameters params = new AuditQueryParameters();
 | |
|             params.setApplicationName(CMIS_CHANGELOG_AUDIT_APPLICATION);
 | |
|             params.setForward(false);
 | |
|             auditService.auditQuery(auditQueryCallback, params, 1);
 | |
|             String entryId = auditQueryCallback.getEntryId();
 | |
|             // MNT-13529
 | |
|             // add initial change log token
 | |
|             latestChangeLogToken = entryId == null ? "0" : entryId;
 | |
|         }
 | |
| 
 | |
|         // compile repository info
 | |
|         RepositoryInfoImpl ri = new RepositoryInfoImpl();
 | |
| 
 | |
|         ri.setId(currentDescriptor.getId());
 | |
|         ri.setName(currentDescriptor.getName());
 | |
|         ri.setDescription(currentDescriptor.getName());
 | |
|         ri.setVendorName("Alfresco");
 | |
|         ri.setProductName("Alfresco " + descriptorService.getServerDescriptor().getEdition());
 | |
|         ri.setProductVersion(currentDescriptor.getVersion());
 | |
|         NodeRef rootNodeRef = getRootNodeRef();
 | |
|         ri.setRootFolder(constructObjectId(rootNodeRef, null));
 | |
|         ri.setCmisVersion(cmisVersion);
 | |
| 
 | |
|         ri.setChangesIncomplete(true);
 | |
|         ri.setChangesOnType(Arrays.asList(new BaseTypeId[] { BaseTypeId.CMIS_DOCUMENT, BaseTypeId.CMIS_FOLDER }));
 | |
|         ri.setLatestChangeLogToken(latestChangeLogToken);
 | |
|         ri.setPrincipalAnonymous(AuthenticationUtil.getGuestUserName());
 | |
|         ri.setPrincipalAnyone(PermissionService.ALL_AUTHORITIES);
 | |
| 
 | |
|         RepositoryCapabilitiesImpl repCap = new RepositoryCapabilitiesImpl();
 | |
|         ri.setCapabilities(repCap);
 | |
| 
 | |
|         repCap.setAllVersionsSearchable(false);
 | |
|         repCap.setCapabilityAcl(CapabilityAcl.MANAGE);
 | |
|         repCap.setCapabilityChanges(auditEnabled ? CapabilityChanges.OBJECTIDSONLY : CapabilityChanges.NONE);
 | |
|         repCap.setCapabilityContentStreamUpdates(CapabilityContentStreamUpdates.ANYTIME);
 | |
|         repCap.setCapabilityJoin(CapabilityJoin.NONE);
 | |
|         repCap.setCapabilityQuery(CapabilityQuery.BOTHCOMBINED);
 | |
|         repCap.setCapabilityRendition(CapabilityRenditions.READ);
 | |
|         repCap.setIsPwcSearchable(false);
 | |
|         repCap.setIsPwcUpdatable(true);
 | |
|         repCap.setSupportsGetDescendants(true);
 | |
|         repCap.setSupportsGetFolderTree(true);
 | |
|         repCap.setSupportsMultifiling(true);
 | |
|         repCap.setSupportsUnfiling(false);
 | |
|         repCap.setSupportsVersionSpecificFiling(false);
 | |
| 
 | |
|         AclCapabilitiesDataImpl aclCap = new AclCapabilitiesDataImpl();
 | |
|         ri.setAclCapabilities(aclCap);
 | |
| 
 | |
|         aclCap.setAclPropagation(AclPropagation.PROPAGATE);
 | |
|         aclCap.setSupportedPermissions(SupportedPermissions.BOTH);
 | |
|         aclCap.setPermissionDefinitionData(repositoryPermissions);
 | |
|         aclCap.setPermissionMappingData(permissionMappings);
 | |
| 
 | |
|         return ri;
 | |
|     }
 | |
| 
 | |
|     private List<PermissionDefinition> getRepositoryPermissions()
 | |
|     {
 | |
|         ArrayList<PermissionDefinition> result = new ArrayList<PermissionDefinition>();
 | |
| 
 | |
|         Set<PermissionReference> all = permissionModelDao.getAllExposedPermissions();
 | |
|         for (PermissionReference pr : all)
 | |
|         {
 | |
|             result.add(createPermissionDefinition(pr));
 | |
|         }
 | |
| 
 | |
|         PermissionReference allPermission = permissionModelDao.getPermissionReference(null,
 | |
|                 PermissionService.ALL_PERMISSIONS);
 | |
|         result.add(createPermissionDefinition(allPermission));
 | |
| 
 | |
|         PermissionDefinitionDataImpl cmisPermission;
 | |
| 
 | |
|         cmisPermission = new PermissionDefinitionDataImpl();
 | |
|         cmisPermission.setId(BasicPermissions.READ);
 | |
|         cmisPermission.setDescription("CMIS Read");
 | |
|         result.add(cmisPermission);
 | |
| 
 | |
|         cmisPermission = new PermissionDefinitionDataImpl();
 | |
|         cmisPermission.setId(BasicPermissions.WRITE);
 | |
|         cmisPermission.setDescription("CMIS Write");
 | |
|         result.add(cmisPermission);
 | |
| 
 | |
|         cmisPermission = new PermissionDefinitionDataImpl();
 | |
|         cmisPermission.setId(BasicPermissions.ALL);
 | |
|         cmisPermission.setDescription("CMIS All");
 | |
|         result.add(cmisPermission);
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     private PermissionDefinition createPermissionDefinition(PermissionReference pr)
 | |
|     {
 | |
|         PermissionDefinitionDataImpl permission = new PermissionDefinitionDataImpl();
 | |
|         permission.setId(pr.getQName().toString() + "." + pr.getName());
 | |
|         permission.setDescription(permission.getId());
 | |
| 
 | |
|         return permission;
 | |
|     }
 | |
| 
 | |
|     private Map<String, PermissionMapping> getPermissionMappings()
 | |
|     {
 | |
|         Map<String, PermissionMapping> result = new HashMap<String, PermissionMapping>();
 | |
| 
 | |
|         for (CMISAllowedActionEnum e : EnumSet.allOf(CMISAllowedActionEnum.class))
 | |
|         {
 | |
|             for (Map.Entry<String, List<String>> m : e.getPermissionMapping().entrySet())
 | |
|             {
 | |
|                 PermissionMappingDataImpl mapping = new PermissionMappingDataImpl();
 | |
|                 mapping.setKey(m.getKey());
 | |
|                 mapping.setPermissions(m.getValue());
 | |
| 
 | |
|                 result.put(mapping.getKey(), mapping);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
|     
 | |
|     private CMISRenditionMapping getRenditionMapping()
 | |
|     {
 | |
|         CMISRenditionMapping renditionMapping = (CMISRenditionMapping)singletonCache.get(KEY_CMIS_RENDITION_MAPPING_NODEREF);
 | |
|         if (renditionMapping == null)
 | |
|         {
 | |
|             renditionMapping = new CMISRenditionMapping(nodeService, contentService, renditionService,
 | |
|                     transactionService, kindToRenditionNames);
 | |
|             
 | |
|             singletonCache.put(KEY_CMIS_RENDITION_MAPPING_NODEREF, renditionMapping);
 | |
|         }
 | |
|         return renditionMapping;
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|      * (non-Javadoc)
 | |
|      * @see org.alfresco.repo.dictionary.DictionaryListener#onDictionaryInit()
 | |
|      */
 | |
|     @Override
 | |
|     public void onDictionaryInit()
 | |
|     {
 | |
|     }        
 | |
|     /*
 | |
|      * (non-Javadoc)
 | |
|      * @see org.alfresco.repo.dictionary.DictionaryListener#afterDictionaryInit()
 | |
|      */
 | |
|     @Override
 | |
|     public void afterDictionaryInit()
 | |
|     {
 | |
|         this.ignoreChildrenQNames = new HashSet<QName>(this.ignoreChildren.size(), 1);
 | |
|         for (String prefixString : this.ignoreChildren)
 | |
|         {
 | |
|             try
 | |
|             {
 | |
|                 this.ignoreChildrenQNames.add(QName.createQName(prefixString, this.namespaceService));
 | |
|             }
 | |
|             catch (Exception e)
 | |
|             {
 | |
|                 logger.warn("Couldn't create QName from " + prefixString, e);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     /*
 | |
|      * (non-Javadoc)
 | |
|      * @see org.alfresco.repo.dictionary.DictionaryListener#afterDictionaryDestroy()
 | |
|      */
 | |
|     @Override
 | |
|     public void afterDictionaryDestroy()
 | |
|     {
 | |
|     }
 | |
| }
 |