mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Merged V3.2 to HEAD
16780: Fix failing unit test - HeartBeat now needs to be constructed inside a transaction. 16765: Merged DEV/BELARUS/V3.2-2009_10_05 to V3.2 16754: ETHREEOH-2534: SPP does not authenticate when authentication chain contains both alfrescoNtlm and passthru types. - NTLM Authentication handler for Sharepoint module was implemented as singleton. But after it was integrated into Alfresco Authentication Subsystem, instance of this object is created for each type of NTLM authentication. As result static field with NTLM flags was rewrited for each instance. Bug was resolved by removing static indicator. 16751: LDAP sync improvements - Correction to the way retried transactional errors are reported - Addition of unit test for synchronization with a mock user registry generating a large volume of users, groups and associations 16749: Removed UserUsageBootstrapJob from scheduled jobs and moved UserUsageTrackingComponent to bootstrap - files missed from CHK-9619 16748: User Usage Tracking Component bootstrapped synchronously to avoid its expensive queries across all users 'stepping on top of' other bootstrap activity such as LDAP synchronization - Its startup messages are no longer masked out by log4j.properties - Logged ETHREEOH-3009 regarding upgrade impact of new faster queries 16747: Lower impact of HeartBeat service on server performance - More efficient AuthorityService APIs used to determine the total number of groups and users more efficiently - Queries of all users and groups done synchronously at startup only 16746: Improvements for faster user and group lookup and association on a large repository (unfortunately intertwined) - NodeService getChildAssocRefsByTypeQNames query rewritten to use a subquery to force a more logical evaluation order on MySQL - NodeService getChildAssocs method made to use more efficient getChildAssocRefsByTypeQNames DAO call when a type qname but no assoc qname is specified - NodeService getUsersWithoutUsage / getUsersWithUsage queries rewritten to avoid an expensive outer join on all users - PersonService getPersonIgnoreCase query corrected to include the type QName ID of the child associations it is querying (thus avoiding unnecessarily triggering duplicate person removal) - PersonService now supports an optional boolean argument to getPerson that indicates whether the auto-create + home folder creation behaviour should be triggered. - AuthorityDAOImpl now uses false argument to getPerson call to avoid lazy home folder creation during creation of group associations - AuthorityDAOImpl now specifies assoc type to getChildAssocs in getAllAuthoritiesInZone and findAuthorities calls so that the more efficient query variant is used - Redundant personExists() call removed from authorityServiceImpl git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@16914 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -462,6 +462,44 @@
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- User usage tracking (requires a query across all users on startup) -->
|
||||
<bean id="userUsageTrackingComponent" class="org.alfresco.repo.usage.UserUsageTrackingComponent">
|
||||
<property name="transactionService">
|
||||
<ref bean="transactionService"/>
|
||||
</property>
|
||||
<property name="contentUsageImpl">
|
||||
<ref bean="contentUsageImpl"/>
|
||||
</property>
|
||||
<!-- The store in which people are persisted-->
|
||||
<property name="personStoreUrl">
|
||||
<value>${spaces.store}</value>
|
||||
</property>
|
||||
<property name="nodeService">
|
||||
<ref bean="nodeService"/>
|
||||
</property>
|
||||
<property name="nodeDaoService">
|
||||
<ref bean="nodeDaoService"/>
|
||||
</property>
|
||||
<property name="usageService">
|
||||
<ref bean="usageService"/>
|
||||
</property>
|
||||
<property name="tenantAdminService">
|
||||
<ref bean="tenantAdminService" />
|
||||
</property>
|
||||
<property name="tenantService">
|
||||
<ref bean="tenantService" />
|
||||
</property>
|
||||
<property name="clearBatchSize">
|
||||
<value>50</value>
|
||||
</property>
|
||||
<property name="updateBatchSize">
|
||||
<value>50</value>
|
||||
</property>
|
||||
<property name="enabled">
|
||||
<value>${system.usages.enabled}</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- User registry synchronization jobs (e.g. LDAP) -->
|
||||
<bean id="Synchronization" class="org.alfresco.repo.management.subsystems.ChildApplicationContextFactory" parent="abstractPropertyBackedBean">
|
||||
<property name="autoStart">
|
||||
|
@@ -277,44 +277,7 @@
|
||||
<value>0 30 3 * * ?</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="userUsageTrackingComponent" class="org.alfresco.repo.usage.UserUsageTrackingComponent">
|
||||
<property name="transactionService">
|
||||
<ref bean="transactionService"/>
|
||||
</property>
|
||||
<property name="contentUsageImpl">
|
||||
<ref bean="contentUsageImpl"/>
|
||||
</property>
|
||||
<!-- The store in which people are persisted-->
|
||||
<property name="personStoreUrl">
|
||||
<value>${spaces.store}</value>
|
||||
</property>
|
||||
<property name="nodeService">
|
||||
<ref bean="nodeService"/>
|
||||
</property>
|
||||
<property name="nodeDaoService">
|
||||
<ref bean="nodeDaoService"/>
|
||||
</property>
|
||||
<property name="usageService">
|
||||
<ref bean="usageService"/>
|
||||
</property>
|
||||
<property name="tenantAdminService">
|
||||
<ref bean="tenantAdminService" />
|
||||
</property>
|
||||
<property name="tenantService">
|
||||
<ref bean="tenantService" />
|
||||
</property>
|
||||
<property name="clearBatchSize">
|
||||
<value>50</value>
|
||||
</property>
|
||||
<property name="updateBatchSize">
|
||||
<value>50</value>
|
||||
</property>
|
||||
<property name="enabled">
|
||||
<value>${system.usages.enabled}</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
|
||||
<!-- enable scheduler property to activate -->
|
||||
<bean id="userUsageCollapseJob" class="org.alfresco.util.TriggerBean">
|
||||
<property name="jobDetail">
|
||||
@@ -348,39 +311,6 @@
|
||||
|
||||
</bean>
|
||||
|
||||
<!-- enable scheduler property to activate -->
|
||||
<bean id="userUsageBootstrapJob" class="org.alfresco.util.TriggerBean">
|
||||
<property name="jobDetail">
|
||||
<bean id="userUsageBootstrapDetail" class="org.springframework.scheduling.quartz.JobDetailBean">
|
||||
<property name="jobClass">
|
||||
<value>org.alfresco.repo.usage.UserUsageBootstrapJob</value>
|
||||
</property>
|
||||
<property name="jobDataAsMap">
|
||||
<map>
|
||||
<entry key="userUsageTrackingComponent">
|
||||
<ref bean="userUsageTrackingComponent" />
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
|
||||
<!-- enable this to activate bean -->
|
||||
|
||||
<property name="scheduler">
|
||||
<ref bean="schedulerFactory" />
|
||||
</property>
|
||||
|
||||
<!-- start after scheduler bootstrap (0 minutes) and run once -->
|
||||
<property name="startDelayMinutes">
|
||||
<value>0</value>
|
||||
</property>
|
||||
<property name="repeatCount">
|
||||
<value>0</value>
|
||||
</property>
|
||||
|
||||
</bean>
|
||||
|
||||
<!-- There is a job available to purge old deploymentattempt nodes -->
|
||||
<!-- from the repository. The maximum age of the node can be configured. -->
|
||||
<!-- See the wiki (http://wiki.alfresco.com/wikiDeployment) for details -->
|
||||
|
@@ -437,32 +437,38 @@
|
||||
assoc.id
|
||||
</query>
|
||||
|
||||
<query name="node.GetChildAssocRefsByTypeQNames">
|
||||
<sql-query name="node.GetChildAssocRefsByTypeQNames">
|
||||
<return-scalar column="id" type="long"/>
|
||||
<return-scalar column="type_qname_id" type="long"/>
|
||||
<return-scalar column="qname_ns_id" type="long"/>
|
||||
<return-scalar column="qname_localname" type="string"/>
|
||||
<return-scalar column="child_node_name" type="string"/>
|
||||
<return-scalar column="child_node_name_crc" type="long"/>
|
||||
<return-scalar column="is_primary" type="boolean"/>
|
||||
<return-scalar column="assoc_index" type="integer"/>
|
||||
<return-scalar column="id" type="long"/>
|
||||
<return-scalar column="protocol" type="string"/>
|
||||
<return-scalar column="identifier" type="string"/>
|
||||
<return-scalar column="uuid" type="string"/>
|
||||
select
|
||||
assoc.id,
|
||||
assoc.typeQNameId,
|
||||
assoc.qnameNamespaceId,
|
||||
assoc.qnameLocalName,
|
||||
assoc.childNodeName,
|
||||
assoc.childNodeNameCrc,
|
||||
assoc.isPrimary,
|
||||
assoc.index,
|
||||
child.id,
|
||||
store.protocol,
|
||||
store.identifier,
|
||||
child.uuid
|
||||
a.id,
|
||||
a.type_qname_id,
|
||||
a.qname_ns_id,
|
||||
a.qname_localname,
|
||||
a.child_node_name,
|
||||
a.child_node_name_crc,
|
||||
a.is_primary,
|
||||
a.assoc_index,
|
||||
n.id,
|
||||
s.protocol,
|
||||
s.identifier,
|
||||
n.uuid
|
||||
from
|
||||
org.alfresco.repo.domain.hibernate.ChildAssocImpl as assoc
|
||||
join assoc.parent as parent
|
||||
join assoc.child as child
|
||||
join child.store as store
|
||||
where
|
||||
parent.id = :parentId and
|
||||
assoc.typeQNameId in (:childAssocTypeQNameIds)
|
||||
order by
|
||||
assoc.index,
|
||||
assoc.id
|
||||
</query>
|
||||
(select * from alf_child_assoc a where parent_node_id = :parentId and type_qname_id in (:childAssocTypeQNameIds)) a
|
||||
inner join alf_node n on a.child_node_id=n.id
|
||||
inner join alf_store s on n.store_id=s.id
|
||||
order by a.assoc_index, a.id
|
||||
</sql-query>
|
||||
|
||||
<query name="node.GetChildAssocRefsByTypeQNameAndQName">
|
||||
select
|
||||
@@ -720,11 +726,11 @@
|
||||
alf_node n
|
||||
JOIN alf_store s ON (s.id = n.store_id AND n.type_qname_id = :personTypeQNameID)
|
||||
JOIN alf_node_properties p1 ON (p1.node_id = n.id AND p1.qname_id = :usernamePropQNameID)
|
||||
LEFT JOIN alf_node_properties p2 ON (p2.node_id = n.id AND p2.qname_id = :sizeCurrentPropQNameID)
|
||||
JOIN alf_node_properties p2 ON (p2.node_id = n.id AND p2.qname_id = :sizeCurrentPropQNameID)
|
||||
WHERE
|
||||
s.protocol = :storeProtocol AND
|
||||
s.identifier = :storeIdentifier AND
|
||||
(p2.persisted_type_n IS NULL OR p2.persisted_type_n = 0) AND
|
||||
p2.persisted_type_n = 0 AND
|
||||
p1.string_value != 'System'
|
||||
</sql-query>
|
||||
|
||||
@@ -738,11 +744,11 @@
|
||||
alf_node n
|
||||
JOIN alf_store s ON (s.id = n.store_id AND n.type_qname_id = :personTypeQNameID)
|
||||
JOIN alf_node_properties p1 ON (p1.node_id = n.id AND p1.qname_id = :usernamePropQNameID)
|
||||
LEFT JOIN alf_node_properties p2 ON (p2.node_id = n.id AND p2.qname_id = :sizeCurrentPropQNameID)
|
||||
JOIN alf_node_properties p2 ON (p2.node_id = n.id AND p2.qname_id = :sizeCurrentPropQNameID)
|
||||
WHERE
|
||||
s.protocol = :storeProtocol AND
|
||||
s.identifier = :storeIdentifier AND
|
||||
(p2.persisted_type_n != 0 AND p2.persisted_type_n IS NOT NULL) AND
|
||||
p2.persisted_type_n != 0 AND
|
||||
p1.string_value != 'System'
|
||||
</sql-query>
|
||||
|
||||
|
@@ -412,6 +412,7 @@
|
||||
JOIN alf_store s on s.id = n.store_id
|
||||
WHERE
|
||||
c.qname_localname = :userNameLowerCase AND
|
||||
c.type_qname_id = :assocTypeQNameID AND
|
||||
p.qname_id = :qnamePropId AND
|
||||
n.type_qname_id = :qnameTypeId AND
|
||||
n.node_deleted = :False AND
|
||||
|
@@ -1456,65 +1456,136 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
|
||||
Long nodeId = nodePair.getFirst();
|
||||
|
||||
final List<ChildAssociationRef> results = new ArrayList<ChildAssociationRef>(100);
|
||||
|
||||
// if the type is the wildcard type, and the qname is not a search, then use a shortcut query
|
||||
if (typeQNamePattern.equals(RegexQNamePattern.MATCH_ALL) && qnamePattern instanceof QName)
|
||||
|
||||
if (qnamePattern instanceof QName)
|
||||
{
|
||||
NodeDaoService.ChildAssocRefQueryCallback callback = new NodeDaoService.ChildAssocRefQueryCallback()
|
||||
// Both explicit QNames
|
||||
if (typeQNamePattern instanceof QName)
|
||||
{
|
||||
public boolean handle(
|
||||
Pair<Long, ChildAssociationRef> childAssocPair,
|
||||
Pair<Long, NodeRef> parentNodePair,
|
||||
Pair<Long, NodeRef> childNodePair)
|
||||
NodeDaoService.ChildAssocRefQueryCallback callback = new NodeDaoService.ChildAssocRefQueryCallback()
|
||||
{
|
||||
results.add(childAssocPair.getSecond());
|
||||
return false;
|
||||
}
|
||||
};
|
||||
// Get all child associations with the specific qualified name
|
||||
nodeDaoService.getChildAssocs(nodeId, (QName)qnamePattern, callback);
|
||||
}
|
||||
else if (typeQNamePattern instanceof QName && qnamePattern instanceof QName)
|
||||
{
|
||||
NodeDaoService.ChildAssocRefQueryCallback callback = new NodeDaoService.ChildAssocRefQueryCallback()
|
||||
public boolean handle(Pair<Long, ChildAssociationRef> childAssocPair,
|
||||
Pair<Long, NodeRef> parentNodePair, Pair<Long, NodeRef> childNodePair)
|
||||
{
|
||||
results.add(childAssocPair.getSecond());
|
||||
return false;
|
||||
}
|
||||
};
|
||||
// Get all child associations with the specific qualified name
|
||||
nodeDaoService.getChildAssocsByTypeQNameAndQName(nodeId, (QName) typeQNamePattern,
|
||||
(QName) qnamePattern, callback);
|
||||
}
|
||||
// Type is explicit, local qname is pattern
|
||||
else
|
||||
{
|
||||
public boolean handle(
|
||||
Pair<Long, ChildAssociationRef> childAssocPair,
|
||||
Pair<Long, NodeRef> parentNodePair,
|
||||
Pair<Long, NodeRef> childNodePair)
|
||||
NodeDaoService.ChildAssocRefQueryCallback callback;
|
||||
if (typeQNamePattern.equals(RegexQNamePattern.MATCH_ALL))
|
||||
{
|
||||
results.add(childAssocPair.getSecond());
|
||||
return false;
|
||||
callback = new NodeDaoService.ChildAssocRefQueryCallback()
|
||||
{
|
||||
public boolean handle(Pair<Long, ChildAssociationRef> childAssocPair,
|
||||
Pair<Long, NodeRef> parentNodePair, Pair<Long, NodeRef> childNodePair)
|
||||
{
|
||||
results.add(childAssocPair.getSecond());
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
// Get all child associations with the specific qualified name
|
||||
nodeDaoService.getChildAssocsByTypeQNameAndQName(
|
||||
nodeId,
|
||||
(QName)typeQNamePattern,
|
||||
(QName)qnamePattern,
|
||||
callback);
|
||||
else
|
||||
{
|
||||
callback = new NodeDaoService.ChildAssocRefQueryCallback()
|
||||
{
|
||||
public boolean handle(Pair<Long, ChildAssociationRef> childAssocPair,
|
||||
Pair<Long, NodeRef> parentNodePair, Pair<Long, NodeRef> childNodePair)
|
||||
{
|
||||
ChildAssociationRef assocRef = childAssocPair.getSecond();
|
||||
QName assocTypeQName = assocRef.getTypeQName();
|
||||
if (!typeQNamePattern.isMatch(assocTypeQName))
|
||||
{
|
||||
// No match
|
||||
return false;
|
||||
}
|
||||
results.add(assocRef);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// Get all child associations with the specific qualified name
|
||||
nodeDaoService.getChildAssocs(nodeId, (QName) qnamePattern, callback);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NodeDaoService.ChildAssocRefQueryCallback callback = new NodeDaoService.ChildAssocRefQueryCallback()
|
||||
// Local qname is pattern, type name is explicit
|
||||
if (typeQNamePattern instanceof QName)
|
||||
{
|
||||
public boolean handle(Pair<Long, ChildAssociationRef> childAssocPair, Pair<Long, NodeRef> parentNodePair, Pair<Long, NodeRef> childNodePair)
|
||||
NodeDaoService.ChildAssocRefQueryCallback callback;
|
||||
// if the type is the wildcard type, and the qname is not a search, then use a shortcut query
|
||||
if (qnamePattern.equals(RegexQNamePattern.MATCH_ALL))
|
||||
{
|
||||
ChildAssociationRef assocRef = childAssocPair.getSecond();
|
||||
QName assocTypeQName = assocRef.getTypeQName();
|
||||
QName assocQName = assocRef.getQName();
|
||||
if (!qnamePattern.isMatch(assocQName) || !typeQNamePattern.isMatch(assocTypeQName))
|
||||
callback = new NodeDaoService.ChildAssocRefQueryCallback()
|
||||
{
|
||||
// No match
|
||||
public boolean handle(Pair<Long, ChildAssociationRef> childAssocPair,
|
||||
Pair<Long, NodeRef> parentNodePair, Pair<Long, NodeRef> childNodePair)
|
||||
{
|
||||
results.add(childAssocPair.getSecond());
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
callback = new NodeDaoService.ChildAssocRefQueryCallback()
|
||||
{
|
||||
public boolean handle(Pair<Long, ChildAssociationRef> childAssocPair,
|
||||
Pair<Long, NodeRef> parentNodePair, Pair<Long, NodeRef> childNodePair)
|
||||
{
|
||||
ChildAssociationRef assocRef = childAssocPair.getSecond();
|
||||
QName assocQName = assocRef.getQName();
|
||||
if (!qnamePattern.isMatch(assocQName))
|
||||
{
|
||||
// No match
|
||||
return false;
|
||||
}
|
||||
results.add(assocRef);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Get all child associations with the specific type qualified name
|
||||
nodeDaoService.getChildAssocsByTypeQNames(nodeId, Collections.singletonList((QName) typeQNamePattern),
|
||||
callback);
|
||||
|
||||
}
|
||||
// Local qname is pattern, type name is pattern
|
||||
else
|
||||
{
|
||||
NodeDaoService.ChildAssocRefQueryCallback callback = new NodeDaoService.ChildAssocRefQueryCallback()
|
||||
{
|
||||
public boolean handle(Pair<Long, ChildAssociationRef> childAssocPair,
|
||||
Pair<Long, NodeRef> parentNodePair, Pair<Long, NodeRef> childNodePair)
|
||||
{
|
||||
ChildAssociationRef assocRef = childAssocPair.getSecond();
|
||||
QName assocTypeQName = assocRef.getTypeQName();
|
||||
QName assocQName = assocRef.getQName();
|
||||
if (!qnamePattern.isMatch(assocQName) || !typeQNamePattern.isMatch(assocTypeQName))
|
||||
{
|
||||
// No match
|
||||
return false;
|
||||
}
|
||||
results.add(assocRef);
|
||||
return false;
|
||||
}
|
||||
results.add(assocRef);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
// Get all child associations
|
||||
nodeDaoService.getChildAssocs(nodeId, callback, false);
|
||||
};
|
||||
// Get all child associations
|
||||
nodeDaoService.getChildAssocs(nodeId, callback, false);
|
||||
}
|
||||
}
|
||||
|
||||
// sort the results
|
||||
List<ChildAssociationRef> orderedList = reorderChildAssocs(results);
|
||||
// done
|
||||
|
@@ -47,6 +47,7 @@ import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||
import org.alfresco.service.cmr.security.AuthorityType;
|
||||
import org.alfresco.service.cmr.security.NoSuchPersonException;
|
||||
import org.alfresco.service.cmr.security.PersonService;
|
||||
import org.alfresco.service.namespace.NamespacePrefixResolver;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
@@ -219,7 +220,8 @@ public class AuthorityDAOImpl implements AuthorityDAO
|
||||
NodeRef container = getAuthorityContainer();
|
||||
if (container != null)
|
||||
{
|
||||
for (ChildAssociationRef childRef : nodeService.getChildAssocs(container))
|
||||
for (ChildAssociationRef childRef : nodeService.getChildAssocs(container,
|
||||
ContentModel.ASSOC_CHILDREN, RegexQNamePattern.MATCH_ALL))
|
||||
{
|
||||
addAuthorityNameIfMatches(authorities, childRef.getQName().getLocalName(), type, pattern);
|
||||
}
|
||||
@@ -234,9 +236,11 @@ public class AuthorityDAOImpl implements AuthorityDAO
|
||||
{
|
||||
if (container != null)
|
||||
{
|
||||
for (ChildAssociationRef childRef : nodeService.getChildAssocs(container))
|
||||
for (ChildAssociationRef childRef : nodeService.getChildAssocs(container,
|
||||
ContentModel.ASSOC_IN_ZONE, RegexQNamePattern.MATCH_ALL))
|
||||
{
|
||||
addAuthorityNameIfMatches(authorities, childRef.getQName().getLocalName(), type, pattern);
|
||||
addAuthorityNameIfMatches(authorities, childRef.getQName().getLocalName(), type,
|
||||
pattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -375,35 +379,30 @@ public class AuthorityDAOImpl implements AuthorityDAO
|
||||
|
||||
private NodeRef getAuthorityOrNull(String name)
|
||||
{
|
||||
if (AuthorityType.getAuthorityType(name).equals(AuthorityType.USER))
|
||||
try
|
||||
{
|
||||
if (!personService.personExists(name))
|
||||
if (AuthorityType.getAuthorityType(name).equals(AuthorityType.USER))
|
||||
{
|
||||
return null;
|
||||
return personService.getPerson(name, false);
|
||||
}
|
||||
return personService.getPerson(name);
|
||||
}
|
||||
else if (AuthorityType.getAuthorityType(name).equals(AuthorityType.GUEST))
|
||||
{
|
||||
if (!personService.personExists(name))
|
||||
else if (AuthorityType.getAuthorityType(name).equals(AuthorityType.GUEST))
|
||||
{
|
||||
return null;
|
||||
return personService.getPerson(name, false);
|
||||
}
|
||||
return personService.getPerson(name);
|
||||
}
|
||||
else if (AuthorityType.getAuthorityType(name).equals(AuthorityType.ADMIN))
|
||||
{
|
||||
if (!personService.personExists(name))
|
||||
else if (AuthorityType.getAuthorityType(name).equals(AuthorityType.ADMIN))
|
||||
{
|
||||
return null;
|
||||
return personService.getPerson(name, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
List<ChildAssociationRef> results = nodeService.getChildAssocs(getAuthorityContainer(),
|
||||
ContentModel.ASSOC_CHILDREN, QName.createQName("cm", name, namespacePrefixResolver));
|
||||
return results.isEmpty() ? null : results.get(0).getChildRef();
|
||||
}
|
||||
return personService.getPerson(name);
|
||||
}
|
||||
else
|
||||
catch (NoSuchPersonException e)
|
||||
{
|
||||
List<ChildAssociationRef> results = nodeService.getChildAssocs(getAuthorityContainer(), ContentModel.ASSOC_CHILDREN, QName.createQName("cm", name,
|
||||
namespacePrefixResolver));
|
||||
return results.isEmpty() ? null : results.get(0).getChildRef();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -575,7 +574,7 @@ public class AuthorityDAOImpl implements AuthorityDAO
|
||||
NodeRef zoneRef = getZone(zoneName);
|
||||
if (zoneRef != null)
|
||||
{
|
||||
for (ChildAssociationRef childRef : nodeService.getChildAssocs(zoneRef))
|
||||
for (ChildAssociationRef childRef : nodeService.getChildAssocs(zoneRef, ContentModel.ASSOC_IN_ZONE, RegexQNamePattern.MATCH_ALL))
|
||||
{
|
||||
addAuthorityNameIfMatches(authorities, childRef.getQName().getLocalName(), type, null);
|
||||
}
|
||||
|
@@ -338,13 +338,6 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean
|
||||
|
||||
public void addAuthority(String parentName, String childName)
|
||||
{
|
||||
if (AuthorityType.getAuthorityType(childName).equals(AuthorityType.USER))
|
||||
{
|
||||
if(!personService.personExists(childName))
|
||||
{
|
||||
throw new AuthorityException("The person "+childName+" does not exist and can not be added to a group");
|
||||
}
|
||||
}
|
||||
authorityDAO.addAuthority(parentName, childName);
|
||||
}
|
||||
|
||||
|
@@ -57,6 +57,7 @@ public class PersonDaoImpl extends HibernateDaoSupport implements PersonDao
|
||||
private static final String QUERY_PERSON_GET_ALL_PEOPLE = "person.getAllPeople";
|
||||
|
||||
private QNameDAO qnameDAO;
|
||||
private Long assocTypeQNameID;
|
||||
private Long qNamePropId;
|
||||
private Long qNameTypeId;
|
||||
private LocaleDAO localeDAO;
|
||||
@@ -79,6 +80,7 @@ public class PersonDaoImpl extends HibernateDaoSupport implements PersonDao
|
||||
|
||||
public void init()
|
||||
{
|
||||
assocTypeQNameID = qnameDAO.getOrCreateQName(ContentModel.ASSOC_CHILDREN).getFirst();
|
||||
qNamePropId = qnameDAO.getOrCreateQName(ContentModel.PROP_USERNAME).getFirst();
|
||||
qNameTypeId = qnameDAO.getOrCreateQName(ContentModel.TYPE_PERSON).getFirst();
|
||||
}
|
||||
@@ -112,6 +114,7 @@ public class PersonDaoImpl extends HibernateDaoSupport implements PersonDao
|
||||
public Object doInHibernate(Session session)
|
||||
{
|
||||
SQLQuery query = (SQLQuery) session.getNamedQuery(QUERY_PERSON_GET_PERSON_IGNORE_CASE);
|
||||
query.setParameter("assocTypeQNameID", assocTypeQNameID);
|
||||
query.setParameter("qnamePropId", qNamePropId);
|
||||
query.setParameter("qnameTypeId", qNameTypeId);
|
||||
query.setParameter("userNameLowerCase", searchUserName.toLowerCase()); // Lowercase: ETHREEOH-1431
|
||||
|
@@ -18,7 +18,7 @@
|
||||
* 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
|
||||
* FLOSS exception. You should have received a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
@@ -255,7 +255,25 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
|
||||
* @return NodeRef of the person as specified by the username
|
||||
* @throws NoSuchPersonException
|
||||
*/
|
||||
public NodeRef getPerson(final String userName)
|
||||
public NodeRef getPerson(String userName)
|
||||
{
|
||||
return getPerson(userName, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the person NodeRef for a username key. Depending on the <code>autoCreate</code> parameter and
|
||||
* configuration missing people will be created if not found, else a NoSuchPersonException exception will be thrown.
|
||||
*
|
||||
* @param userName
|
||||
* of the person NodeRef to retrieve
|
||||
* @param autoCreate
|
||||
* should we auto-create the person node and home folder if they don't exist? (and configuration allows
|
||||
* us to)
|
||||
* @return NodeRef of the person as specified by the username
|
||||
* @throws NoSuchPersonException
|
||||
* if the person doesn't exist and can't be created
|
||||
*/
|
||||
public NodeRef getPerson(final String userName, final boolean autoCreate)
|
||||
{
|
||||
// MT share - for activity service system callback
|
||||
if (tenantService.isEnabled() && (AuthenticationUtil.SYSTEM_USER_NAME.equals(AuthenticationUtil.getRunAsUser())) && tenantService.isTenantUser(userName))
|
||||
@@ -266,17 +284,17 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
|
||||
{
|
||||
public NodeRef doWork() throws Exception
|
||||
{
|
||||
return getPersonImpl(userName);
|
||||
return getPersonImpl(userName, autoCreate);
|
||||
}
|
||||
}, tenantService.getDomainUser(AuthenticationUtil.getSystemUserName(), tenantDomain));
|
||||
}
|
||||
else
|
||||
{
|
||||
return getPersonImpl(userName);
|
||||
return getPersonImpl(userName, autoCreate);
|
||||
}
|
||||
}
|
||||
|
||||
private NodeRef getPersonImpl(String userName)
|
||||
private NodeRef getPersonImpl(String userName, boolean autoCreate)
|
||||
{
|
||||
if(userName == null)
|
||||
{
|
||||
@@ -290,7 +308,7 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
|
||||
if (personNode == null)
|
||||
{
|
||||
TxnReadState txnReadState = AlfrescoTransactionSupport.getTransactionReadState();
|
||||
if (createMissingPeople() && txnReadState == TxnReadState.TXN_READ_WRITE)
|
||||
if (autoCreate && createMissingPeople() && txnReadState == TxnReadState.TXN_READ_WRITE)
|
||||
{
|
||||
// We create missing people AND are in a read-write txn
|
||||
return createMissingPerson(userName);
|
||||
@@ -300,11 +318,11 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
|
||||
throw new NoSuchPersonException(userName);
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (autoCreate)
|
||||
{
|
||||
makeHomeFolderIfRequired(personNode);
|
||||
return personNode;
|
||||
}
|
||||
return personNode;
|
||||
}
|
||||
|
||||
public boolean personExists(String caseSensitiveUserName)
|
||||
|
@@ -452,9 +452,12 @@ public class BatchProcessor<T> implements BatchMonitor
|
||||
/** The number of successfully processed entries. */
|
||||
private int txnSuccesses;
|
||||
|
||||
/** The current entry being processed in the transaction */
|
||||
private String txnEntryId;
|
||||
|
||||
/** The last error. */
|
||||
private Throwable txnLastError;
|
||||
|
||||
|
||||
/** The last error entry id. */
|
||||
private String txnLastErrorEntryId;
|
||||
|
||||
@@ -467,7 +470,7 @@ public class BatchProcessor<T> implements BatchMonitor
|
||||
reset();
|
||||
for (T entry : this.batch)
|
||||
{
|
||||
String txnEntryId = this.worker.getIdentifier(entry);
|
||||
this.txnEntryId = this.worker.getIdentifier(entry);
|
||||
synchronized (BatchProcessor.this)
|
||||
{
|
||||
BatchProcessor.this.currentEntryId = txnEntryId;
|
||||
@@ -479,9 +482,6 @@ public class BatchProcessor<T> implements BatchMonitor
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
this.txnLastError = t;
|
||||
this.txnLastErrorEntryId = txnEntryId;
|
||||
this.txnErrors++;
|
||||
if (RetryingTransactionHelper.extractRetryCause(t) == null)
|
||||
{
|
||||
if (BatchProcessor.logger.isWarnEnabled())
|
||||
@@ -489,6 +489,9 @@ public class BatchProcessor<T> implements BatchMonitor
|
||||
BatchProcessor.logger.warn(getProcessName() + ": Failed to process entry \"" + txnEntryId
|
||||
+ "\".", t);
|
||||
}
|
||||
this.txnLastError = t;
|
||||
this.txnLastErrorEntryId = txnEntryId;
|
||||
this.txnErrors++;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -514,6 +517,9 @@ public class BatchProcessor<T> implements BatchMonitor
|
||||
// If the callback was in its own transaction, it must have run out of retries
|
||||
if (this.splitTxns)
|
||||
{
|
||||
this.txnLastError = t;
|
||||
this.txnLastErrorEntryId = this.txnEntryId;
|
||||
this.txnErrors++;
|
||||
if (BatchProcessor.logger.isWarnEnabled())
|
||||
{
|
||||
BatchProcessor.logger.warn(getProcessName() + ": Failed to process entry \""
|
||||
|
@@ -405,6 +405,31 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
|
||||
tearDownTestUsersAndGroups();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests synchronization of group associations in a zone with a larger volume of authorities.
|
||||
*
|
||||
* @throws Exception
|
||||
* the exception
|
||||
*/
|
||||
public void dontTestAssocs() throws Exception
|
||||
{
|
||||
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
|
||||
{
|
||||
public Object execute() throws Throwable
|
||||
{
|
||||
List<NodeDescription> groups = new ArrayList<NodeDescription>(new RandomGroupCollection(1000,
|
||||
ChainingUserRegistrySynchronizerTest.this.authorityService.getAllAuthoritiesInZone(
|
||||
AuthorityService.ZONE_AUTH_EXT_PREFIX + "Z0", null)));
|
||||
ChainingUserRegistrySynchronizerTest.this.applicationContextManager
|
||||
.setUserRegistries(new MockUserRegistry("Z0", Collections.<NodeDescription> emptyList(), groups));
|
||||
;
|
||||
ChainingUserRegistrySynchronizerTest.this.synchronizer.synchronize(true, true);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
tearDownTestUsersAndGroups();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a description of a test group.
|
||||
*
|
||||
@@ -719,12 +744,12 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
|
||||
|
||||
public boolean hasNext()
|
||||
{
|
||||
return pos < size;
|
||||
return this.pos < RandomPersonCollection.this.size;
|
||||
}
|
||||
|
||||
public NodeDescription next()
|
||||
{
|
||||
pos++;
|
||||
this.pos++;
|
||||
return newPerson("U" + GUID.generate());
|
||||
}
|
||||
|
||||
@@ -743,7 +768,7 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
|
||||
@Override
|
||||
public int size()
|
||||
{
|
||||
return size;
|
||||
return this.size;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -758,21 +783,39 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
|
||||
/** The collection size. */
|
||||
private final int size;
|
||||
|
||||
/** The persons. */
|
||||
private final List<NodeDescription> persons;
|
||||
/** The authorities. */
|
||||
private final List<String> authorities;
|
||||
|
||||
/**
|
||||
* The Constructor.
|
||||
*
|
||||
* @param size
|
||||
* the collection size
|
||||
* @param persons
|
||||
* the persons
|
||||
* @param authorities
|
||||
* the authorities
|
||||
*/
|
||||
public RandomGroupCollection(int size, List<NodeDescription> persons)
|
||||
public RandomGroupCollection(int size, Set<String> authorities)
|
||||
{
|
||||
this.size = size;
|
||||
this.persons = persons;
|
||||
this.authorities = new ArrayList<String>(authorities);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Constructor.
|
||||
*
|
||||
* @param size
|
||||
* the collection size
|
||||
* @param authorities
|
||||
* the authorities
|
||||
*/
|
||||
public RandomGroupCollection(int size, Collection<NodeDescription> persons)
|
||||
{
|
||||
this.size = size;
|
||||
this.authorities = new ArrayList<String>(persons.size());
|
||||
for (NodeDescription nodeDescription : persons)
|
||||
{
|
||||
this.authorities.add((String) nodeDescription.getProperties().get(ContentModel.PROP_USERNAME));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -789,19 +832,21 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
|
||||
|
||||
public boolean hasNext()
|
||||
{
|
||||
return pos < size;
|
||||
return this.pos < RandomGroupCollection.this.size;
|
||||
}
|
||||
|
||||
public NodeDescription next()
|
||||
{
|
||||
pos++;
|
||||
String[] personNames = new String[10];
|
||||
for (int i = 0; i < personNames.length; i++)
|
||||
this.pos++;
|
||||
String[] authorityNames = new String[17];
|
||||
for (int i = 0; i < authorityNames.length; i++)
|
||||
{
|
||||
personNames[i] = (String) persons.get((int) (Math.random() * (double) (persons.size() - 1)))
|
||||
.getProperties().get(ContentModel.PROP_USERNAME);
|
||||
authorityNames[i] = ChainingUserRegistrySynchronizerTest.this.authorityService
|
||||
.getShortName((String) RandomGroupCollection.this.authorities
|
||||
.get((int) (Math.random() * (double) (RandomGroupCollection.this.authorities
|
||||
.size() - 1))));
|
||||
}
|
||||
return newGroup("G" + GUID.generate(), personNames);
|
||||
return newGroup("G" + GUID.generate(), authorityNames);
|
||||
}
|
||||
|
||||
public void remove()
|
||||
@@ -819,7 +864,7 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
|
||||
@Override
|
||||
public int size()
|
||||
{
|
||||
return size;
|
||||
return this.size;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -52,7 +52,6 @@ import org.alfresco.repo.security.authentication.AuthenticationContext;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.repo.site.SiteAVMBootstrap;
|
||||
import org.alfresco.repo.usage.UserUsageBootstrapJob;
|
||||
import org.alfresco.repo.usage.UserUsageTrackingComponent;
|
||||
import org.alfresco.repo.workflow.WorkflowDeployer;
|
||||
import org.alfresco.service.cmr.admin.RepoAdminService;
|
||||
@@ -937,7 +936,7 @@ public class MultiTAdminServiceImpl implements TenantAdminService, ApplicationCo
|
||||
spacesImporterBootstrap.bootstrap();
|
||||
|
||||
// calculate any missing usages
|
||||
UserUsageTrackingComponent userUsageTrackingComponent = (UserUsageTrackingComponent)ctx.getBean(UserUsageBootstrapJob.KEY_COMPONENT);
|
||||
UserUsageTrackingComponent userUsageTrackingComponent = (UserUsageTrackingComponent)ctx.getBean("userUsageTrackingComponent");
|
||||
userUsageTrackingComponent.bootstrapInternal();
|
||||
|
||||
logger.debug("Bootstrapped store: " + tenantService.getBaseName(bootstrapStoreRef));
|
||||
|
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 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.repo.usage;
|
||||
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobDataMap;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
|
||||
/**
|
||||
* Bootstraps user's content usage. This job is performed once at startup.
|
||||
*
|
||||
* If usages are enabled (as specified by 'system.usages.enabled=true' repository property) then will calculate
|
||||
* usages for all users that have no current usage.
|
||||
*
|
||||
* If usages are disabled (as specified by 'system.usages.enabled=false' repository property) then will clear
|
||||
* current usages for all users.
|
||||
*/
|
||||
public class UserUsageBootstrapJob implements Job
|
||||
{
|
||||
public static final String KEY_COMPONENT = "userUsageTrackingComponent";
|
||||
|
||||
public void execute(JobExecutionContext context) throws JobExecutionException
|
||||
{
|
||||
JobDataMap jobData = context.getJobDetail().getJobDataMap();
|
||||
UserUsageTrackingComponent usageComponent = (UserUsageTrackingComponent) jobData.get(KEY_COMPONENT);
|
||||
if (usageComponent == null)
|
||||
{
|
||||
throw new JobExecutionException("Missing job data: " + KEY_COMPONENT);
|
||||
}
|
||||
// perform the content usage bootstrap
|
||||
usageComponent.bootstrap();
|
||||
}
|
||||
}
|
@@ -48,17 +48,19 @@ import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.usage.UsageService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.AbstractLifecycleBean;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
/**
|
||||
* User Usage Tracking Component - to allow user usages to be collapsed or re-calculated
|
||||
*
|
||||
* - used by UserUsageCollapseJob to collapse usage deltas.
|
||||
* - used by UserUsageBootstrapJob to either clear all usages or (re-)calculate all missing usages.
|
||||
* - used on bootstrap to either clear all usages or (re-)calculate all missing usages.
|
||||
*/
|
||||
public class UserUsageTrackingComponent
|
||||
public class UserUsageTrackingComponent extends AbstractLifecycleBean
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(UserUsageTrackingComponent.class);
|
||||
|
||||
@@ -156,8 +158,9 @@ public class UserUsageTrackingComponent
|
||||
}
|
||||
}
|
||||
|
||||
// called once on startup
|
||||
public void bootstrap()
|
||||
|
||||
@Override
|
||||
protected void onBootstrap(ApplicationEvent event)
|
||||
{
|
||||
// default domain
|
||||
bootstrapInternal();
|
||||
@@ -176,7 +179,7 @@ public class UserUsageTrackingComponent
|
||||
}
|
||||
}, tenantAdminService.getDomainUser(AuthenticationUtil.getSystemUserName(), tenant.getTenantDomain()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void bootstrapInternal()
|
||||
@@ -212,6 +215,12 @@ public class UserUsageTrackingComponent
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onShutdown(ApplicationEvent event)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clear content usage for all users that have a usage.
|
||||
*/
|
||||
|
@@ -68,6 +68,22 @@ public interface PersonService
|
||||
@Auditable(parameters = {"userName"})
|
||||
public NodeRef getPerson(String userName);
|
||||
|
||||
/**
|
||||
* Retrieve the person NodeRef for a username key. Depending on the <code>autoCreate</code> parameter and
|
||||
* configuration missing people will be created if not found, else a NoSuchPersonException exception will be thrown.
|
||||
*
|
||||
* @param userName
|
||||
* of the person NodeRef to retrieve
|
||||
* @param autoCreate
|
||||
* should we auto-create the person node and home folder if they don't exist? (and configuration allows
|
||||
* us to)
|
||||
* @return NodeRef of the person as specified by the username
|
||||
* @throws NoSuchPersonException
|
||||
* if the person doesn't exist and can't be created
|
||||
*/
|
||||
@Auditable(parameters = {"userName", "autoCreate"})
|
||||
public NodeRef getPerson(final String userName, final boolean autoCreate);
|
||||
|
||||
/**
|
||||
* Check if a person exists.
|
||||
*
|
||||
|
Reference in New Issue
Block a user