Merged V3.1 to HEAD

13065: SiteService - listSites() "nameFilter" and "sizeFilter" now implemented. Optimization to retrieve the Site Root noderef and cache it within the SiteService.

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@13556 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Kevin Roast
2009-03-11 10:37:53 +00:00
parent 205b7b7697
commit 9d3fd6680d
4 changed files with 177 additions and 48 deletions

View File

@@ -64,13 +64,15 @@
<property name="fileFolderService" ref="FileFolderService"/> <property name="fileFolderService" ref="FileFolderService"/>
<property name="searchService" ref="SearchService"/> <property name="searchService" ref="SearchService"/>
<property name="namespaceService" ref="NamespaceService"/> <property name="namespaceService" ref="NamespaceService"/>
<property name="permissionService" ref="PermissionService" /> <property name="permissionService" ref="PermissionService"/>
<property name="authenticationComponent" ref="authenticationComponent"/> <property name="authenticationComponent" ref="authenticationComponent"/>
<property name="personService" ref="PersonService"/> <property name="personService" ref="PersonService"/>
<property name="activityService" ref="activityService"/> <property name="activityService" ref="activityService"/>
<property name="taggingService" ref="TaggingService"/> <property name="taggingService" ref="TaggingService"/>
<property name="authorityService" ref="authorityService"/> <property name="authorityService" ref="authorityService"/>
<property name="dictionaryService" ref="DictionaryService"/> <property name="dictionaryService" ref="DictionaryService"/>
<property name="tenantAdminService" ref="tenantAdminService"/>
<property name="transactionHelper" ref="retryingTransactionHelper"/>
<property name="sitesXPath"> <property name="sitesXPath">
<value>./${spaces.company_home.childname}/st:sites</value> <value>./${spaces.company_home.childname}/st:sites</value>
</property> </property>

View File

@@ -27,17 +27,23 @@ package org.alfresco.repo.site;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.activities.ActivityType; import org.alfresco.repo.activities.ActivityType;
import org.alfresco.repo.search.QueryParameterDefImpl;
import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil; 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.TenantService; import org.alfresco.repo.tenant.TenantService;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.activities.ActivityService; import org.alfresco.service.cmr.activities.ActivityService;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.model.FileInfo;
@@ -46,6 +52,8 @@ import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef; 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.SearchService; import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.AccessPermission; import org.alfresco.service.cmr.security.AccessPermission;
import org.alfresco.service.cmr.security.AccessStatus; import org.alfresco.service.cmr.security.AccessStatus;
@@ -75,11 +83,11 @@ import org.json.JSONObject;
*/ */
public class SiteServiceImpl implements SiteService, SiteModel public class SiteServiceImpl implements SiteService, SiteModel
{ {
private static final String GROUP_SITE_PREFIX = PermissionService.GROUP_PREFIX + "site_";
/** Logger */ /** Logger */
private static Log logger = LogFactory.getLog(SiteServiceImpl.class); private static Log logger = LogFactory.getLog(SiteServiceImpl.class);
private static final String GROUP_SITE_PREFIX = PermissionService.GROUP_PREFIX + "site_";
/** The DM store where site's are kept */ /** The DM store where site's are kept */
public static final StoreRef SITE_STORE = new StoreRef("workspace://SpacesStore"); public static final StoreRef SITE_STORE = new StoreRef("workspace://SpacesStore");
@@ -88,6 +96,9 @@ public class SiteServiceImpl implements SiteService, SiteModel
private static final String SITE_PREFIX = "site_"; private static final String SITE_PREFIX = "site_";
private static final int GROUP_PREFIX_LENGTH = SITE_PREFIX.length() + PermissionService.GROUP_PREFIX.length(); private static final int GROUP_PREFIX_LENGTH = SITE_PREFIX.length() + PermissionService.GROUP_PREFIX.length();
/** Site home ref cache (Tennant aware) */
private Map<String, NodeRef> siteHomeRefs = new ConcurrentHashMap<String, NodeRef>(4);
private String sitesXPath; private String sitesXPath;
@@ -115,6 +126,9 @@ public class SiteServiceImpl implements SiteService, SiteModel
private AuthorityService authorityService; private AuthorityService authorityService;
private DictionaryService dictionaryService; private DictionaryService dictionaryService;
private TenantService tenantService; private TenantService tenantService;
private TenantAdminService tenantAdminService;
private RetryingTransactionHelper retryingTransactionHelper;
/** /**
* Set the path to the location of the sites root folder. For example: * Set the path to the location of the sites root folder. For example:
@@ -229,6 +243,22 @@ public class SiteServiceImpl implements SiteService, SiteModel
this.tenantService = tenantService; this.tenantService = tenantService;
} }
/**
* 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;
}
/** /**
* Checks that all necessary properties and services have been provided. * Checks that all necessary properties and services have been provided.
*/ */
@@ -465,8 +495,7 @@ public class SiteServiceImpl implements SiteService, SiteModel
{ {
// TODO // TODO
// For now just return the site root, later we may build folder // For now just return the site root, later we may build folder
// structure based on the shortname to // structure based on the shortname to spread the sites about
// spread the sites about
return getSiteRoot(); return getSiteRoot();
} }
@@ -477,57 +506,128 @@ public class SiteServiceImpl implements SiteService, SiteModel
*/ */
private NodeRef getSiteRoot() private NodeRef getSiteRoot()
{ {
// Get the root 'sites' folder String tenantDomain = tenantAdminService.getCurrentUserDomain();
NodeRef rootNodeRef = this.nodeService.getRootNode(SITE_STORE); NodeRef siteHomeRef = siteHomeRefs.get(tenantDomain);
List<NodeRef> results = this.searchService.selectNodes( if (siteHomeRef == null)
rootNodeRef, {
sitesXPath, siteHomeRef = AuthenticationUtil.runAs(new RunAsWork<NodeRef>()
null, {
namespaceService, public NodeRef doWork() throws Exception
false, {
SearchService.LANGUAGE_XPATH); return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<NodeRef>()
if (results.size() == 0) {
{ public NodeRef execute() throws Exception
// No root site folder exists {
throw new SiteServiceException("No root sites folder exists"); // Get the root 'sites' folder
NodeRef rootNodeRef = nodeService.getRootNode(SITE_STORE);
List<NodeRef> results = searchService.selectNodes(
rootNodeRef,
sitesXPath,
null,
namespaceService,
false,
SearchService.LANGUAGE_XPATH);
if (results.size() == 0)
{
// No root site folder exists
throw new SiteServiceException("No root sites folder exists");
}
else if (results.size() != 1)
{
// More than one root site folder exits
logger.warn("More than one root sites folder exists: \n" + results);
}
return results.get(0);
}
});
}
}, AuthenticationUtil.getSystemUserName());
siteHomeRefs.put(tenantDomain, siteHomeRef);
} }
else if (results.size() != 1) return siteHomeRef;
{
// More than one root site folder exits
logger.warn("More than one root sites folder exists: \n" + results);
}
return results.get(0);
} }
/** /**
* @see org.alfresco.service.cmr.site.SiteService#listSites(java.lang.String, * @see org.alfresco.service.cmr.site.SiteService#listSites(java.lang.String, java.lang.String)
* java.lang.String)
*/ */
public List<SiteInfo> listSites(String nameFilter, String sitePresetFilter) public List<SiteInfo> listSites(String nameFilter, String sitePresetFilter)
{ {
// TODO return listSites(nameFilter, sitePresetFilter, 0);
// - take into consideration the filters set }
// - take into consideration that the sites may not just be in a flat
// list under the site root
// For now just return the list of sites present under the site root /**
* @see org.alfresco.service.cmr.site.SiteService#listSites(java.lang.String, java.lang.String, int)
*/
public List<SiteInfo> listSites(String nameFilter, String sitePresetFilter, int size)
{
List<SiteInfo> result;
// TODO: take into consideration the sitePresetFilter
NodeRef siteRoot = getSiteRoot(); NodeRef siteRoot = getSiteRoot();
List<ChildAssociationRef> assocs = this.nodeService.getChildAssocs( if (nameFilter != null && nameFilter.length() != 0)
siteRoot, ContentModel.ASSOC_CONTAINS,
RegexQNamePattern.MATCH_ALL);
List<SiteInfo> result = new ArrayList<SiteInfo>(assocs.size());
for (ChildAssociationRef assoc : assocs)
{ {
// Ignore any node that is not a "site" // Perform a Lucene search under the Site parent node using *name* search query
NodeRef site = assoc.getChildRef(); QueryParameterDefinition[] params = new QueryParameterDefinition[1];
QName siteClassName = this.nodeService.getType(site); params[0] = new QueryParameterDefImpl(
if (this.dictionaryService.isSubClass(siteClassName, SiteModel.TYPE_SITE) == true) ContentModel.PROP_NAME,
{ dictionaryService.getDataType(
result.add(createSiteInfo(site)); DataTypeDefinition.TEXT),
true,
nameFilter);
// get the sites that match the specified names
StringBuilder query = new StringBuilder(128);
query.append("+PARENT:\"").append(siteRoot.toString())
.append("\" +@cm\\:name:\"*").append(nameFilter).append("*\"");
ResultSet results = this.searchService.query(
siteRoot.getStoreRef(),
SearchService.LANGUAGE_LUCENE,
query.toString(),
params);
result = new ArrayList<SiteInfo>(results.length());
try
{
for (NodeRef site : results.getNodeRefs())
{
// Ignore any node type that is not a "site"
QName siteClassName = this.nodeService.getType(site);
if (this.dictionaryService.isSubClass(siteClassName, SiteModel.TYPE_SITE) == true)
{
result.add(createSiteInfo(site));
// break on max size limit reached
if (result.size() == size) break;
}
}
}
finally
{
results.close();
} }
} }
else
{
// Get ALL sites - this may be a very slow operation if there are many sites...
List<ChildAssociationRef> assocs = this.nodeService.getChildAssocs(
siteRoot, ContentModel.ASSOC_CONTAINS,
RegexQNamePattern.MATCH_ALL);
result = new ArrayList<SiteInfo>(assocs.size());
for (ChildAssociationRef assoc : assocs)
{
// Ignore any node type that is not a "site"
NodeRef site = assoc.getChildRef();
QName siteClassName = this.nodeService.getType(site);
if (this.dictionaryService.isSubClass(siteClassName, SiteModel.TYPE_SITE) == true)
{
result.add(createSiteInfo(site));
// break on max size limit reached
if (result.size() == size) break;
}
}
}
return result; return result;
} }

View File

@@ -122,14 +122,31 @@ public class ScriptSiteService extends BaseScopableProcessorExtension
*/ */
public Site[] listSites(String nameFilter, String sitePresetFilter) public Site[] listSites(String nameFilter, String sitePresetFilter)
{ {
List<SiteInfo> siteInfos = this.siteService.listSites(nameFilter, sitePresetFilter); return listSites(nameFilter, sitePresetFilter, 0);
}
/**
* List the sites available in the repository. The returned list can optionally be filtered by name and site
* preset.
* <p>
* If no filters are specified then all the available sites are returned.
*
* @param nameFilter name filter
* @param sitePresetFilter site preset filter
* @param size max results size crop if >0
*
* @return Site[] a list of the site filtered as appropriate
*/
public Site[] listSites(String nameFilter, String sitePresetFilter, int size)
{
List<SiteInfo> siteInfos = this.siteService.listSites(nameFilter, sitePresetFilter, size);
List<Site> sites = new ArrayList<Site>(siteInfos.size()); List<Site> sites = new ArrayList<Site>(siteInfos.size());
for (SiteInfo siteInfo : siteInfos) for (SiteInfo siteInfo : siteInfos)
{ {
sites.add(new Site(siteInfo, this.serviceRegistry, this.siteService, getScope())); sites.add(new Site(siteInfo, this.serviceRegistry, this.siteService, getScope()));
} }
return (Site[])sites.toArray(new Site[sites.size()]); return (Site[])sites.toArray(new Site[sites.size()]);
} }
/** /**
* List all the sites that the specified user has an explicit membership to. * List all the sites that the specified user has an explicit membership to.

View File

@@ -41,6 +41,16 @@ public interface SiteService
*/ */
SiteInfo createSite(String sitePreset, String shortName, String title, String description, SiteVisibility visibility); SiteInfo createSite(String sitePreset, String shortName, String title, String description, SiteVisibility visibility);
/**
* List the available sites. This list can optionally be filtered by site name and/or site preset.
*
* @param nameFilter name filter
* @param sitePresetFilter site preset filter
* @param size list maximum size or zero for all
* @return List<SiteInfo> list of site information
*/
List<SiteInfo> listSites(String nameFilter, String sitePresetFilter, int size);
/** /**
* List the available sites. This list can optionally be filtered by site name and/or site preset. * List the available sites. This list can optionally be filtered by site name and/or site preset.
* *