Transactional safe cache added to PersonServiceImpl to cache person NodeRefs against usernames.

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@6036 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Kevin Roast
2007-06-20 16:30:49 +00:00
parent 1073576c12
commit aa41ae3768
3 changed files with 220 additions and 114 deletions

View File

@@ -173,26 +173,30 @@
--> -->
<!-- The person service. --> <!-- The person service. -->
<bean id="personService" class="org.alfresco.repo.security.person.PersonServiceImpl"> <bean id="personService" class="org.alfresco.repo.security.person.PersonServiceImpl" init-method="init">
<property name="nodeService"> <property name="nodeService">
<ref bean="nodeService" /> <ref bean="nodeService" />
</property> </property>
<property name="searchService"> <property name="searchService">
<ref bean="admSearchService" /> <ref bean="admSearchService" />
</property> </property>
<property name="permissionServiceSPI"> <property name="permissionServiceSPI">
<ref bean="permissionServiceImpl" /> <ref bean="permissionServiceImpl" />
</property> </property>
<property name="authorityService"> <property name="authorityService">
<ref bean="authorityService" /> <ref bean="authorityService" />
</property> </property>
<property name="namespacePrefixResolver"> <property name="namespacePrefixResolver">
<ref bean="namespaceService" /> <ref bean="namespaceService" />
</property> </property>
<property name="policyComponent">
<ref bean="policyComponent"/>
</property>
<property name="personCache">
<ref bean="personCache" />
</property>
<!-- Configurable properties. --> <!-- Configurable properties. -->
<!-- --> <!-- -->
<!-- TODO: --> <!-- TODO: -->
@@ -214,7 +218,7 @@
<property name="createMissingPeople"> <property name="createMissingPeople">
<value>${server.transaction.allow-writes}</value> <value>${server.transaction.allow-writes}</value>
</property> </property>
<property name="userNamesAreCaseSensitive"> <property name="userNamesAreCaseSensitive">
<value>${user.name.caseSensitive}</value> <value>${user.name.caseSensitive}</value>
</property> </property>
<!-- New properties after 1.4.0 to deal with duplicate user ids when found --> <!-- New properties after 1.4.0 to deal with duplicate user ids when found -->
@@ -235,20 +239,20 @@
<bean name="homeFolderManager" class="org.alfresco.repo.security.person.HomeFolderManager"> <bean name="homeFolderManager" class="org.alfresco.repo.security.person.HomeFolderManager">
<property name="nodeService"> <property name="nodeService">
<ref bean="nodeService" /> <ref bean="nodeService" />
</property> </property>
<property name="policyComponent"> <property name="policyComponent">
<ref bean="policyComponent" /> <ref bean="policyComponent" />
</property> </property>
<property name="defaultProvider"> <property name="defaultProvider">
<ref bean="personalHomeFolderProvider" /> <ref bean="personalHomeFolderProvider" />
</property> </property>
</bean> </bean>
<bean name="companyHomeFolderProvider" class="org.alfresco.repo.security.person.ExistingPathBasedHomeFolderProvider"> <bean name="companyHomeFolderProvider" class="org.alfresco.repo.security.person.ExistingPathBasedHomeFolderProvider">
<property name="serviceRegistry"> <property name="serviceRegistry">
<ref bean="ServiceRegistry" /> <ref bean="ServiceRegistry" />
</property> </property>
<property name="path"> <property name="path">
<value>/${spaces.company_home.childname}</value> <value>/${spaces.company_home.childname}</value>
</property> </property>
@@ -256,14 +260,14 @@
<value>${spaces.store}</value> <value>${spaces.store}</value>
</property> </property>
<property name="homeFolderManager"> <property name="homeFolderManager">
<ref bean="homeFolderManager" /> <ref bean="homeFolderManager" />
</property> </property>
</bean> </bean>
<bean name="guestHomeFolderProvider" class="org.alfresco.repo.security.person.ExistingPathBasedHomeFolderProvider"> <bean name="guestHomeFolderProvider" class="org.alfresco.repo.security.person.ExistingPathBasedHomeFolderProvider">
<property name="serviceRegistry"> <property name="serviceRegistry">
<ref bean="ServiceRegistry" /> <ref bean="ServiceRegistry" />
</property> </property>
<property name="path"> <property name="path">
<value>/${spaces.company_home.childname}/${spaces.guest_home.childname}</value> <value>/${spaces.company_home.childname}/${spaces.guest_home.childname}</value>
</property> </property>
@@ -271,8 +275,8 @@
<value>${spaces.store}</value> <value>${spaces.store}</value>
</property> </property>
<property name="homeFolderManager"> <property name="homeFolderManager">
<ref bean="homeFolderManager" /> <ref bean="homeFolderManager" />
</property> </property>
<property name="userPemissions"> <property name="userPemissions">
<set> <set>
<value>Consumer</value> <value>Consumer</value>
@@ -282,14 +286,14 @@
<bean name="bootstrapHomeFolderProvider" class="org.alfresco.repo.security.person.BootstrapHomeFolderProvider"> <bean name="bootstrapHomeFolderProvider" class="org.alfresco.repo.security.person.BootstrapHomeFolderProvider">
<property name="homeFolderManager"> <property name="homeFolderManager">
<ref bean="homeFolderManager" /> <ref bean="homeFolderManager" />
</property> </property>
</bean> </bean>
<bean name="personalHomeFolderProvider" class="org.alfresco.repo.security.person.UIDBasedHomeFolderProvider"> <bean name="personalHomeFolderProvider" class="org.alfresco.repo.security.person.UIDBasedHomeFolderProvider">
<property name="serviceRegistry"> <property name="serviceRegistry">
<ref bean="ServiceRegistry" /> <ref bean="ServiceRegistry" />
</property> </property>
<property name="path"> <property name="path">
<value>/${spaces.company_home.childname}</value> <value>/${spaces.company_home.childname}</value>
</property> </property>
@@ -297,8 +301,8 @@
<value>${spaces.store}</value> <value>${spaces.store}</value>
</property> </property>
<property name="homeFolderManager"> <property name="homeFolderManager">
<ref bean="homeFolderManager" /> <ref bean="homeFolderManager" />
</property> </property>
<property name="inheritsPermissionsOnCreate"> <property name="inheritsPermissionsOnCreate">
<value>false</value> <value>false</value>
</property> </property>
@@ -313,11 +317,11 @@
</set> </set>
</property> </property>
</bean> </bean>
<bean name="userHomesHomeFolderProvider" class="org.alfresco.repo.security.person.UIDBasedHomeFolderProvider"> <bean name="userHomesHomeFolderProvider" class="org.alfresco.repo.security.person.UIDBasedHomeFolderProvider">
<property name="serviceRegistry"> <property name="serviceRegistry">
<ref bean="ServiceRegistry" /> <ref bean="ServiceRegistry" />
</property> </property>
<property name="path"> <property name="path">
<value>/${spaces.company_home.childname}/${spaces.user_homes.childname}</value> <value>/${spaces.company_home.childname}/${spaces.user_homes.childname}</value>
</property> </property>
@@ -325,8 +329,8 @@
<value>${spaces.store}</value> <value>${spaces.store}</value>
</property> </property>
<property name="homeFolderManager"> <property name="homeFolderManager">
<ref bean="homeFolderManager" /> <ref bean="homeFolderManager" />
</property> </property>
<property name="inheritsPermissionsOnCreate"> <property name="inheritsPermissionsOnCreate">
<value>false</value> <value>false</value>
</property> </property>

View File

@@ -207,5 +207,42 @@
<value>10</value> <value>10</value>
</property> </property>
</bean> </bean>
<!-- ===================================== -->
<!-- Person username to NodeRef cache -->
<!-- ===================================== -->
<!-- The cross-transaction shared cache for Person -->
<bean name="personSharedCache" class="org.alfresco.repo.cache.EhCacheAdapter">
<property name="cache">
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean" >
<property name="cacheManager">
<ref bean="internalEHCacheManager" />
</property>
<property name="cacheName">
<value>org.alfresco.cache.personCache</value>
</property>
</bean>
</property>
</bean>
<!-- The transactional cache for Person -->
<bean name="personCache" class="org.alfresco.repo.cache.TransactionalCache">
<property name="sharedCache">
<ref bean="personSharedCache" />
</property>
<property name="cacheManager" >
<ref bean="transactionalEHCacheManager" />
</property>
<!-- Eh cache area -->
<property name="name">
<value>org.alfresco.personTransactionalCache</value>
</property>
<property name="maxCacheSize">
<value>1000</value>
</property>
</bean>
</beans> </beans>

View File

@@ -35,8 +35,12 @@ import java.util.Set;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.authentication.ldap.LDAPPersonExportSource; import org.alfresco.repo.cache.SimpleCache;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.security.permissions.PermissionServiceSPI; import org.alfresco.repo.security.permissions.PermissionServiceSPI;
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;
@@ -49,12 +53,14 @@ import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.NoSuchPersonException; import org.alfresco.service.cmr.security.NoSuchPersonException;
import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.namespace.NamespacePrefixResolver; import org.alfresco.service.namespace.NamespacePrefixResolver;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.util.GUID; import org.alfresco.util.GUID;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
public class PersonServiceImpl implements PersonService public class PersonServiceImpl implements PersonService,
NodeServicePolicies.OnCreateNodePolicy, NodeServicePolicies.BeforeDeleteNodePolicy
{ {
private static Log s_logger = LogFactory.getLog(PersonServiceImpl.class); private static Log s_logger = LogFactory.getLog(PersonServiceImpl.class);
@@ -81,6 +87,8 @@ public class PersonServiceImpl implements PersonService
private PermissionServiceSPI permissionServiceSPI; private PermissionServiceSPI permissionServiceSPI;
private NamespacePrefixResolver namespacePrefixResolver; private NamespacePrefixResolver namespacePrefixResolver;
private PolicyComponent policyComponent;
private boolean createMissingPeople; private boolean createMissingPeople;
@@ -97,6 +105,9 @@ public class PersonServiceImpl implements PersonService
private boolean lastIsBest = true; private boolean lastIsBest = true;
private boolean includeAutoCreated = false; private boolean includeAutoCreated = false;
/** a transactionally-safe cache to be injected */
private SimpleCache<String, NodeRef> personCache;
static static
{ {
@@ -110,9 +121,19 @@ public class PersonServiceImpl implements PersonService
mutableProperties = Collections.unmodifiableSet(props); mutableProperties = Collections.unmodifiableSet(props);
} }
public PersonServiceImpl() /**
* Spring bean init method
*/
public void init()
{ {
super(); this.policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "onCreateNode"),
ContentModel.TYPE_PERSON,
new JavaBehaviour(this, "onCreateNode"));
this.policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "beforeDeleteNode"),
ContentModel.TYPE_PERSON,
new JavaBehaviour(this, "beforeDeleteNode"));
} }
public boolean getUserNamesAreCaseSensitive() public boolean getUserNamesAreCaseSensitive()
@@ -149,7 +170,27 @@ public class PersonServiceImpl implements PersonService
{ {
this.processDuplicates = processDuplicates; this.processDuplicates = processDuplicates;
} }
/**
* Set the username to person cache.
*
* @param personCache a transactionally safe cache
*/
public void setPersonCache(SimpleCache<String, NodeRef> personCache)
{
this.personCache = personCache;
}
/**
* Retrieve the person NodeRef for a username key. Depending on configuration missing people
* will be created if not found, else a NoSuchPersonException exception will be thrown.
*
* @param userName of the person NodeRef to retrieve
*
* @return NodeRef of the person as specified by the username
*
* @throws NoSuchPersonException
*/
public NodeRef getPerson(String userName) public NodeRef getPerson(String userName)
{ {
NodeRef personNode = getPersonOrNull(userName); NodeRef personNode = getPersonOrNull(userName);
@@ -163,7 +204,6 @@ public class PersonServiceImpl implements PersonService
{ {
throw new NoSuchPersonException(userName); throw new NoSuchPersonException(userName);
} }
} }
else else
{ {
@@ -176,83 +216,86 @@ public class PersonServiceImpl implements PersonService
return getPersonOrNull(caseSensitiveUserName) != null; return getPersonOrNull(caseSensitiveUserName) != null;
} }
public NodeRef getPersonOrNull(String searchUserName) private NodeRef getPersonOrNull(String searchUserName)
{ {
NodeRef returnRef = null; NodeRef returnRef = this.personCache.get(searchUserName);
if (returnRef == null)
SearchParameters sp = new SearchParameters();
sp.setLanguage(SearchService.LANGUAGE_LUCENE);
sp.setQuery("TYPE:\\{http\\://www.alfresco.org/model/content/1.0\\}person +@cm\\:userName:\""
+ searchUserName + "\"");
sp.addStore(storeRef);
sp.excludeDataInTheCurrentTransaction(false);
ResultSet rs = null;
boolean singleton = true;
try
{ {
rs = searchService.query(sp); SearchParameters sp = new SearchParameters();
sp.setLanguage(SearchService.LANGUAGE_LUCENE);
for (ResultSetRow row : rs) sp.setQuery("@cm\\:userName:\"" + searchUserName + "\"");
sp.addStore(storeRef);
sp.excludeDataInTheCurrentTransaction(false);
ResultSet rs = null;
boolean singleton = true;
try
{ {
rs = searchService.query(sp);
NodeRef nodeRef = row.getNodeRef();
if (nodeService.exists(nodeRef)) for (ResultSetRow row : rs)
{ {
String realUserName = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty( NodeRef nodeRef = row.getNodeRef();
nodeRef, ContentModel.PROP_USERNAME)); if (nodeService.exists(nodeRef))
if (userNamesAreCaseSensitive)
{ {
if (realUserName.equals(searchUserName)) String realUserName = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(
nodeRef, ContentModel.PROP_USERNAME));
if (userNamesAreCaseSensitive)
{ {
if (returnRef == null) if (realUserName.equals(searchUserName))
{ {
returnRef = nodeRef; if (returnRef == null)
} {
else returnRef = nodeRef;
{ }
singleton = false; else
break; {
singleton = false;
break;
}
} }
} }
} else
else
{
if (realUserName.equalsIgnoreCase(searchUserName))
{ {
if (returnRef == null) if (realUserName.equalsIgnoreCase(searchUserName))
{ {
returnRef = nodeRef; if (returnRef == null)
} {
else returnRef = nodeRef;
{ }
singleton = false; else
break; {
singleton = false;
break;
}
} }
} }
} }
} }
} }
} finally
finally
{
if (rs != null)
{ {
rs.close(); if (rs != null)
{
rs.close();
}
} }
if (singleton)
{
returnRef = returnRef;
}
else
{
returnRef = handleDuplicates(searchUserName);
}
// add to cache
this.personCache.put(searchUserName, returnRef);
} }
return returnRef;
if (singleton)
{
return returnRef;
}
else
{
return handleDuplicates(searchUserName);
}
} }
private NodeRef handleDuplicates(String searchUserName) private NodeRef handleDuplicates(String searchUserName)
@@ -298,8 +341,7 @@ public class PersonServiceImpl implements PersonService
{ {
SearchParameters sp = new SearchParameters(); SearchParameters sp = new SearchParameters();
sp.setLanguage(SearchService.LANGUAGE_LUCENE); sp.setLanguage(SearchService.LANGUAGE_LUCENE);
sp.setQuery("TYPE:\\{http\\://www.alfresco.org/model/content/1.0\\}person +@cm\\:userName:\"" sp.setQuery("@cm\\:userName:\"" + searchUserName + "\"");
+ searchUserName + "\"");
sp.addStore(storeRef); sp.addStore(storeRef);
sp.excludeDataInTheCurrentTransaction(false); sp.excludeDataInTheCurrentTransaction(false);
@@ -349,8 +391,7 @@ public class PersonServiceImpl implements PersonService
{ {
SearchParameters sp = new SearchParameters(); SearchParameters sp = new SearchParameters();
sp.setLanguage(SearchService.LANGUAGE_LUCENE); sp.setLanguage(SearchService.LANGUAGE_LUCENE);
sp.setQuery("TYPE:\\{http\\://www.alfresco.org/model/content/1.0\\}person +@cm\\:userName:\"" sp.setQuery("@cm\\:userName:\"" + searchUserName + "\"");
+ searchUserName + "\"");
sp.addStore(storeRef); sp.addStore(storeRef);
sp.excludeDataInTheCurrentTransaction(false); sp.excludeDataInTheCurrentTransaction(false);
@@ -402,8 +443,7 @@ public class PersonServiceImpl implements PersonService
{ {
SearchParameters sp = new SearchParameters(); SearchParameters sp = new SearchParameters();
sp.setLanguage(SearchService.LANGUAGE_LUCENE); sp.setLanguage(SearchService.LANGUAGE_LUCENE);
sp.setQuery("TYPE:\\{http\\://www.alfresco.org/model/content/1.0\\}person +@cm\\:userName:\"" sp.setQuery("@cm\\:userName:\"" + searchUserName + "\"");
+ searchUserName + "\"");
sp.addStore(storeRef); sp.addStore(storeRef);
sp.excludeDataInTheCurrentTransaction(false); sp.excludeDataInTheCurrentTransaction(false);
if (lastIsBest) if (lastIsBest)
@@ -646,7 +686,30 @@ public class PersonServiceImpl implements PersonService
} }
return nodes; return nodes;
} }
// Policies
/* (non-Javadoc)
* @see org.alfresco.repo.node.NodeServicePolicies.OnCreateNodePolicy#onCreateNode(org.alfresco.service.cmr.repository.ChildAssociationRef)
*/
public void onCreateNode(ChildAssociationRef childAssocRef)
{
NodeRef personRef = childAssocRef.getChildRef();
String username = (String)this.nodeService.getProperty(personRef, ContentModel.PROP_USERNAME);
this.personCache.put(username, personRef);
}
/* (non-Javadoc)
* @see org.alfresco.repo.node.NodeServicePolicies.BeforeDeleteNodePolicy#beforeDeleteNode(org.alfresco.service.cmr.repository.NodeRef)
*/
public void beforeDeleteNode(NodeRef nodeRef)
{
String username = (String)this.nodeService.getProperty(nodeRef, ContentModel.PROP_USERNAME);
this.personCache.remove(username);
}
// IOC Setters
public void setCreateMissingPeople(boolean createMissingPeople) public void setCreateMissingPeople(boolean createMissingPeople)
{ {
this.createMissingPeople = createMissingPeople; this.createMissingPeople = createMissingPeople;
@@ -676,6 +739,11 @@ public class PersonServiceImpl implements PersonService
{ {
this.searchService = searchService; this.searchService = searchService;
} }
public void setPolicyComponent(PolicyComponent policyComponent)
{
this.policyComponent = policyComponent;
}
public void setStoreUrl(String storeUrl) public void setStoreUrl(String storeUrl)
{ {
@@ -693,7 +761,4 @@ public class PersonServiceImpl implements PersonService
} }
return null; return null;
} }
// IOC Setters
} }