mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Cleanly split CMIS interfaces from CMIS implementation.
- org.alfresco.cmis => public interfaces - org.alfresco.cmis.mapping / dictionary / search => implementation git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@13808 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
514
source/java/org/alfresco/cmis/mapping/CMISServicesImpl.java
Normal file
514
source/java/org/alfresco/cmis/mapping/CMISServicesImpl.java
Normal file
@@ -0,0 +1,514 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis.mapping;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.cmis.CMISDictionaryService;
|
||||
import org.alfresco.cmis.CMISPropertyDefinition;
|
||||
import org.alfresco.cmis.CMISPropertyId;
|
||||
import org.alfresco.cmis.CMISServices;
|
||||
import org.alfresco.cmis.CMISTypeDefinition;
|
||||
import org.alfresco.cmis.CMISTypesFilterEnum;
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.model.Repository;
|
||||
import org.alfresco.repo.search.QueryParameterDefImpl;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.repo.tenant.TenantAdminService;
|
||||
import org.alfresco.repo.tenant.TenantDeployer;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.search.QueryParameterDefinition;
|
||||
import org.alfresco.service.cmr.search.ResultSet;
|
||||
import org.alfresco.service.cmr.search.SearchParameters;
|
||||
import org.alfresco.service.cmr.search.SearchService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.AbstractLifecycleBean;
|
||||
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;
|
||||
|
||||
|
||||
/**
|
||||
* CMIS Services Implementation
|
||||
*
|
||||
* @author davidc
|
||||
*/
|
||||
public class CMISServicesImpl implements CMISServices, ApplicationContextAware, ApplicationListener, TenantDeployer
|
||||
{
|
||||
/** Query Parameters */
|
||||
private static final QName PARAM_PARENT = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "parent");
|
||||
private static final QName PARAM_USERNAME = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "username");
|
||||
|
||||
/** Shallow search for all files and folders */
|
||||
private static final String LUCENE_QUERY_SHALLOW_FOLDERS =
|
||||
"+PARENT:\"${cm:parent}\" " +
|
||||
"-TYPE:\"" + ContentModel.TYPE_SYSTEM_FOLDER + "\" " +
|
||||
"+TYPE:\"" + ContentModel.TYPE_FOLDER + "\"";
|
||||
|
||||
/** Shallow search for all files and folders */
|
||||
private static final String LUCENE_QUERY_SHALLOW_FILES =
|
||||
"+PARENT:\"${cm:parent}\" " +
|
||||
"-TYPE:\"" + ContentModel.TYPE_SYSTEM_FOLDER + "\" " +
|
||||
"+TYPE:\"" + ContentModel.TYPE_CONTENT + "\" " +
|
||||
"-ASPECT:\"" + ContentModel.ASPECT_WORKING_COPY + "\"";
|
||||
|
||||
private static final String LUCENE_QUERY_CHECKEDOUT =
|
||||
"+@cm\\:workingCopyOwner:${cm:username}";
|
||||
|
||||
private static final String LUCENE_QUERY_CHECKEDOUT_IN_FOLDER =
|
||||
"+@cm\\:workingCopyOwner:${cm:username} " +
|
||||
"+PARENT:\"${cm:parent}\"";
|
||||
|
||||
|
||||
// dependencies
|
||||
private Repository repository;
|
||||
private RetryingTransactionHelper retryingTransactionHelper;
|
||||
private DictionaryService dictionaryService;
|
||||
private CMISDictionaryService cmisDictionaryService;
|
||||
private SearchService searchService;
|
||||
private NodeService nodeService;
|
||||
private TenantAdminService tenantAdminService;
|
||||
private ProcessorLifecycle lifecycle = new ProcessorLifecycle();
|
||||
|
||||
// CMIS supported version
|
||||
private String cmisVersion = "[undefined]";
|
||||
|
||||
// default CMIS store and path
|
||||
private String defaultRootPath;
|
||||
private Map<String, NodeRef> defaultRootNodeRefs;
|
||||
|
||||
// data types for query
|
||||
private DataTypeDefinition nodeRefDataType;
|
||||
private DataTypeDefinition textDataType;
|
||||
|
||||
|
||||
/**
|
||||
* Sets the supported version of the CMIS specification
|
||||
*
|
||||
* @param cmisVersion
|
||||
*/
|
||||
public void setCMISSpecVersion(String cmisVersion)
|
||||
{
|
||||
this.cmisVersion = cmisVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default root path
|
||||
*
|
||||
* store_type/store_id/path...
|
||||
*
|
||||
* @param path store_type/store_id/path...
|
||||
*/
|
||||
public void setDefaultRootPath(String path)
|
||||
{
|
||||
defaultRootPath = path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the tenant admin service
|
||||
*/
|
||||
public void setTenantAdminService(TenantAdminService tenantAdminService)
|
||||
{
|
||||
this.tenantAdminService = tenantAdminService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets helper that provides transaction callbacks
|
||||
*/
|
||||
public void setTransactionHelper(RetryingTransactionHelper retryingTransactionHelper)
|
||||
{
|
||||
this.retryingTransactionHelper = retryingTransactionHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param dictionaryService
|
||||
*/
|
||||
public void setDictionaryService(DictionaryService dictionaryService)
|
||||
{
|
||||
this.dictionaryService = dictionaryService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cmisDictionaryService
|
||||
*/
|
||||
public void setCMISDictionaryService(CMISDictionaryService cmisDictionaryService)
|
||||
{
|
||||
this.cmisDictionaryService = cmisDictionaryService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param searchService
|
||||
*/
|
||||
public void setSearchService(SearchService searchService)
|
||||
{
|
||||
this.searchService = searchService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nodeService
|
||||
*/
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param repository
|
||||
*/
|
||||
public void setRepository(Repository repository)
|
||||
{
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
|
||||
*/
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
|
||||
{
|
||||
lifecycle.setApplicationContext(applicationContext);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
|
||||
*/
|
||||
public void onApplicationEvent(ApplicationEvent 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)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.tenant.TenantDeployer#onEnableTenant()
|
||||
*/
|
||||
public void onEnableTenant()
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.tenant.TenantDeployer#onDisableTenant()
|
||||
*/
|
||||
public void onDisableTenant()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.tenant.TenantDeployer#init()
|
||||
*/
|
||||
public void init()
|
||||
{
|
||||
// initialise data types
|
||||
nodeRefDataType = dictionaryService.getDataType(DataTypeDefinition.NODE_REF);
|
||||
textDataType = dictionaryService.getDataType(DataTypeDefinition.TEXT);
|
||||
|
||||
// initialise root node ref
|
||||
tenantAdminService.register(this);
|
||||
if (defaultRootNodeRefs == null)
|
||||
{
|
||||
defaultRootNodeRefs = new HashMap<String, NodeRef>(1);
|
||||
}
|
||||
getDefaultRootNodeRef();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.tenant.TenantDeployer#destroy()
|
||||
*/
|
||||
public void destroy()
|
||||
{
|
||||
defaultRootNodeRefs.remove(tenantAdminService.getCurrentUserDomain());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISServices#getCMISVersion()
|
||||
*/
|
||||
public String getCMISVersion()
|
||||
{
|
||||
return cmisVersion;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISServices#getDefaultRootPath()
|
||||
*/
|
||||
public String getDefaultRootPath()
|
||||
{
|
||||
return defaultRootPath;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISServices#getDefaultRootNodeRef()
|
||||
*/
|
||||
public NodeRef getDefaultRootNodeRef()
|
||||
{
|
||||
String tenantDomain = tenantAdminService.getCurrentUserDomain();
|
||||
NodeRef defaultNodeRef = defaultRootNodeRefs.get(tenantDomain);
|
||||
if (defaultNodeRef == null)
|
||||
{
|
||||
defaultNodeRef = AuthenticationUtil.runAs(new RunAsWork<NodeRef>()
|
||||
{
|
||||
public NodeRef doWork() throws Exception
|
||||
{
|
||||
return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<NodeRef>()
|
||||
{
|
||||
public NodeRef execute() throws Exception
|
||||
{
|
||||
return repository.findNodeRef("path", defaultRootPath.split("/"));
|
||||
};
|
||||
});
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
|
||||
if (defaultNodeRef == null)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Default root folder path '" + defaultRootPath + "' not found");
|
||||
}
|
||||
defaultRootNodeRefs.put(tenantDomain, defaultNodeRef);
|
||||
}
|
||||
return defaultNodeRef;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISServices#getDefaultRootStoreRef()
|
||||
*/
|
||||
public StoreRef getDefaultRootStoreRef()
|
||||
{
|
||||
return getDefaultRootNodeRef().getStoreRef();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISServices#getChildren(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.cmis.CMISTypesFilterEnum)
|
||||
*/
|
||||
public NodeRef[] getChildren(NodeRef parent, CMISTypesFilterEnum typesFilter)
|
||||
{
|
||||
if (typesFilter == CMISTypesFilterEnum.ANY)
|
||||
{
|
||||
NodeRef[] folders = queryChildren(parent, CMISTypesFilterEnum.FOLDERS);
|
||||
NodeRef[] docs = queryChildren(parent, CMISTypesFilterEnum.DOCUMENTS);
|
||||
NodeRef[] foldersAndDocs = new NodeRef[folders.length + docs.length];
|
||||
System.arraycopy(folders, 0, foldersAndDocs, 0, folders.length);
|
||||
System.arraycopy(docs, 0, foldersAndDocs, folders.length, docs.length);
|
||||
return foldersAndDocs;
|
||||
}
|
||||
else if (typesFilter == CMISTypesFilterEnum.FOLDERS)
|
||||
{
|
||||
NodeRef[] folders = queryChildren(parent, CMISTypesFilterEnum.FOLDERS);
|
||||
return folders;
|
||||
}
|
||||
else if (typesFilter == CMISTypesFilterEnum.DOCUMENTS)
|
||||
{
|
||||
NodeRef[] docs = queryChildren(parent, CMISTypesFilterEnum.DOCUMENTS);
|
||||
return docs;
|
||||
}
|
||||
|
||||
return new NodeRef[0];
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISServices#getCheckedOut(java.lang.String, org.alfresco.service.cmr.repository.NodeRef, boolean)
|
||||
*/
|
||||
public NodeRef[] getCheckedOut(String username, NodeRef folder, boolean includeDescendants)
|
||||
{
|
||||
SearchParameters params = new SearchParameters();
|
||||
params.setLanguage(SearchService.LANGUAGE_LUCENE);
|
||||
QueryParameterDefinition usernameDef = new QueryParameterDefImpl(PARAM_USERNAME, textDataType, true, username);
|
||||
params.addQueryParameterDefinition(usernameDef);
|
||||
|
||||
if (folder == null)
|
||||
{
|
||||
// get all checked-out items
|
||||
params.setQuery(LUCENE_QUERY_CHECKEDOUT);
|
||||
params.addStore(getDefaultRootStoreRef());
|
||||
}
|
||||
else
|
||||
{
|
||||
// get all checked-out items within folder
|
||||
// NOTE: special-case for all descendants in root folder (treat as all checked-out items)
|
||||
if (includeDescendants && nodeService.getRootNode(folder.getStoreRef()) == folder)
|
||||
{
|
||||
// get all checked-out items within specified folder store
|
||||
params.setQuery(LUCENE_QUERY_CHECKEDOUT);
|
||||
params.addStore(folder.getStoreRef());
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: implement descendants of folder
|
||||
params.setQuery(LUCENE_QUERY_CHECKEDOUT_IN_FOLDER);
|
||||
params.addStore(folder.getStoreRef());
|
||||
QueryParameterDefinition parentDef = new QueryParameterDefImpl(PARAM_PARENT, nodeRefDataType, true, folder.toString());
|
||||
params.addQueryParameterDefinition(parentDef);
|
||||
}
|
||||
}
|
||||
|
||||
ResultSet resultSet = null;
|
||||
try
|
||||
{
|
||||
resultSet = searchService.query(params);
|
||||
List<NodeRef> results = resultSet.getNodeRefs();
|
||||
NodeRef[] nodeRefs = new NodeRef[results.size()];
|
||||
return results.toArray(nodeRefs);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (resultSet != null) resultSet.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Query children helper
|
||||
*
|
||||
* NOTE: Queries for folders only or documents only
|
||||
*
|
||||
* @param parent node to query children for
|
||||
* @param typesFilter folders or documents
|
||||
* @return node children
|
||||
*/
|
||||
private NodeRef[] queryChildren(NodeRef parent, CMISTypesFilterEnum typesFilter)
|
||||
{
|
||||
SearchParameters params = new SearchParameters();
|
||||
params.setLanguage(SearchService.LANGUAGE_LUCENE);
|
||||
params.addStore(parent.getStoreRef());
|
||||
QueryParameterDefinition parentDef = new QueryParameterDefImpl(PARAM_PARENT, nodeRefDataType, true, parent.toString());
|
||||
params.addQueryParameterDefinition(parentDef);
|
||||
|
||||
if (typesFilter == CMISTypesFilterEnum.FOLDERS)
|
||||
{
|
||||
params.setQuery(LUCENE_QUERY_SHALLOW_FOLDERS);
|
||||
}
|
||||
else if (typesFilter == CMISTypesFilterEnum.DOCUMENTS)
|
||||
{
|
||||
params.setQuery(LUCENE_QUERY_SHALLOW_FILES);
|
||||
}
|
||||
|
||||
ResultSet resultSet = null;
|
||||
try
|
||||
{
|
||||
resultSet = searchService.query(params);
|
||||
List<NodeRef> results = resultSet.getNodeRefs();
|
||||
NodeRef[] nodeRefs = new NodeRef[results.size()];
|
||||
return results.toArray(nodeRefs);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (resultSet != null) resultSet.close();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISServices#getProperty(org.alfresco.service.cmr.repository.NodeRef, java.lang.String)
|
||||
*/
|
||||
public Serializable getProperty(NodeRef nodeRef, String propertyName)
|
||||
{
|
||||
QName typeQName = nodeService.getType(nodeRef);
|
||||
CMISTypeDefinition typeDef = cmisDictionaryService.findTypeForClass(typeQName);
|
||||
if (typeDef == null)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Type " + typeQName + " not found in CMIS Dictionary");
|
||||
}
|
||||
CMISPropertyDefinition propDef = cmisDictionaryService.findProperty(propertyName, typeDef);
|
||||
if (propDef == null)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Property " + propertyName + " not found for type " + typeDef.getTypeId() + " in CMIS Dictionary");
|
||||
}
|
||||
return propDef.getPropertyAccessor().getValue(nodeRef);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISServices#getProperties(org.alfresco.service.cmr.repository.NodeRef)
|
||||
*/
|
||||
public Map<String, Serializable> getProperties(NodeRef nodeRef)
|
||||
{
|
||||
QName typeQName = nodeService.getType(nodeRef);
|
||||
CMISTypeDefinition typeDef = cmisDictionaryService.findTypeForClass(typeQName);
|
||||
if (typeDef == null)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Type " + typeQName + " not found in CMIS Dictionary");
|
||||
}
|
||||
Map<CMISPropertyId, CMISPropertyDefinition> propDefs = typeDef.getPropertyDefinitions();
|
||||
Map<String, Serializable> values = new HashMap<String, Serializable>(propDefs.size());
|
||||
for (CMISPropertyDefinition propDef : propDefs.values())
|
||||
{
|
||||
values.put(propDef.getPropertyId().getName(), propDef.getPropertyAccessor().getValue(nodeRef));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISServices#setProperty(org.alfresco.service.cmr.repository.NodeRef, java.lang.String, java.io.Serializable)
|
||||
*/
|
||||
public void setProperty(NodeRef nodeRef, String propertyName, Serializable value)
|
||||
{
|
||||
QName typeQName = nodeService.getType(nodeRef);
|
||||
CMISTypeDefinition typeDef = cmisDictionaryService.findTypeForClass(typeQName);
|
||||
if (typeDef == null)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Type " + typeQName + " not found in CMIS Dictionary");
|
||||
}
|
||||
CMISPropertyDefinition propDef = cmisDictionaryService.findProperty(propertyName, typeDef);
|
||||
if (propDef == null)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Property " + propertyName + " not found for type " + typeDef.getTypeId() + " in CMIS Dictionary");
|
||||
}
|
||||
propDef.getPropertyAccessor().setValue(nodeRef, value);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user