MT - fix user usages for tenants

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@8197 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Jan Vonka
2008-02-05 15:43:17 +00:00
parent fc136a58de
commit 998dbc59f0
8 changed files with 265 additions and 215 deletions

View File

@@ -50,6 +50,8 @@ import org.alfresco.repo.node.db.DbNodeServiceImpl;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
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;
import org.alfresco.service.cmr.attributes.AttributeService;
@@ -870,6 +872,10 @@ public class MultiTAdminServiceImpl extends AbstractLifecycleBean implements Ten
props.put("alfresco_user_store.guestusername", getTenantGuestUser(tenantDomain));
spacesImporterBootstrap.bootstrap();
// calculate any missing usages
UserUsageTrackingComponent userUsageTrackingComponent = (UserUsageTrackingComponent)getApplicationContext().getBean(UserUsageBootstrapJob.KEY_COMPONENT);
userUsageTrackingComponent.bootstrapInternal();
logger.debug("Bootstrapped store: " + tenantService.getBaseName(bootstrapStoreRef));
}

View File

@@ -33,6 +33,7 @@ import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -63,6 +64,7 @@ public class ContentUsageImpl implements ContentUsageService,
private PolicyComponent policyComponent;
private UsageService usageService;
private AuthenticationComponent authenticationComponent;
private TenantService tenantService;
private boolean enabled = true;
@@ -92,6 +94,11 @@ public class ContentUsageImpl implements ContentUsageService,
{
this.authenticationComponent = authenticationComponent;
}
public void setTenantService(TenantService tenantService)
{
this.tenantService = tenantService;
}
public void setEnabled(boolean enabled)
{
@@ -144,7 +151,7 @@ public class ContentUsageImpl implements ContentUsageService,
public void onCreateNode(ChildAssociationRef childAssocRef)
{
NodeRef nodeRef = childAssocRef.getChildRef();
if (stores.contains(nodeRef.getStoreRef().toString()))
if (stores.contains(tenantService.getBaseName(nodeRef.getStoreRef()).toString()))
{
// Get content size
@@ -180,7 +187,7 @@ public class ContentUsageImpl implements ContentUsageService,
Map<QName, Serializable> before,
Map<QName, Serializable> after)
{
if (stores.contains(nodeRef.getStoreRef().toString()))
if (stores.contains(tenantService.getBaseName(nodeRef.getStoreRef()).toString()))
{
// Check for change in content size
@@ -273,7 +280,7 @@ public class ContentUsageImpl implements ContentUsageService,
*/
public void beforeDeleteNode(NodeRef nodeRef)
{
if (stores.contains(nodeRef.getStoreRef().toString()))
if (stores.contains(tenantService.getBaseName(nodeRef.getStoreRef()).toString()))
{
// TODO use data dictionary to get content property
ContentData contentData = (ContentData)nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);

View File

@@ -85,11 +85,11 @@ public class UsageServiceImpl implements UsageService
{
Set<Node> nodes = usageDeltaDao.getUsageDeltaNodes();
// convert nodes to nodeRefs
// convert nodes to nodeRefs (tenant-specific)
Set<NodeRef> results = new HashSet<NodeRef>(nodes.size());
for (Node node : nodes)
{
results.add(tenantService.getBaseName(node.getNodeRef()));
results.add(node.getNodeRef());
}
return results;
}

View File

@@ -40,7 +40,7 @@ import org.quartz.JobExecutionException;
*/
public class UserUsageBootstrapJob implements Job
{
private static final String KEY_COMPONENT = "userUsageBootstrapComponent";
public static final String KEY_COMPONENT = "userUsageTrackingComponent";
public void execute(JobExecutionContext context) throws JobExecutionException
{
@@ -50,7 +50,7 @@ public class UserUsageBootstrapJob implements Job
{
throw new JobExecutionException("Missing job data: " + KEY_COMPONENT);
}
// perform the content usage calculations
usageComponent.execute();
// perform the content usage bootstrap
usageComponent.bootstrap();
}
}

View File

@@ -34,7 +34,7 @@ import org.quartz.JobExecutionException;
*/
public class UserUsageCollapseJob implements Job
{
private static final String KEY_COMPONENT = "userUsageCollapseComponent";
private static final String KEY_COMPONENT = "userUsageTrackingComponent";
public void execute(JobExecutionContext context) throws JobExecutionException
{

View File

@@ -33,6 +33,10 @@ import org.alfresco.model.ContentModel;
import org.alfresco.repo.domain.Node;
import org.alfresco.repo.node.db.NodeDaoService;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.tenant.Tenant;
import org.alfresco.repo.tenant.TenantDeployerService;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.TransactionServiceImpl;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
@@ -58,8 +62,6 @@ public class UserUsageTrackingComponent
private static boolean busy = false;
private boolean bootstrap = false;
private NodeDaoService nodeDaoService;
private TransactionServiceImpl transactionService;
private ContentUsageImpl contentUsageImpl;
@@ -67,6 +69,8 @@ public class UserUsageTrackingComponent
private PersonService personService;
private NodeService nodeService;
private UsageService usageService;
private TenantDeployerService tenantDeployerService;
private TenantService tenantService;
private boolean enabled = true;
@@ -86,11 +90,6 @@ public class UserUsageTrackingComponent
this.contentUsageImpl = contentUsageImpl;
}
public void setBootstrap(boolean bootstrap)
{
this.bootstrap = bootstrap;
}
public void setPersonService(PersonService personService)
{
this.personService = personService;
@@ -106,159 +105,164 @@ public class UserUsageTrackingComponent
this.usageService = usageService;
}
public void setTenantDeployerService(TenantDeployerService tenantDeployerService)
{
this.tenantDeployerService = tenantDeployerService;
}
public void setTenantService(TenantService tenantService)
{
this.tenantService = tenantService;
}
public void setEnabled(boolean enabled)
{
this.enabled = enabled;
}
public void execute()
{
try
if (enabled == true)
{
if (! busy && ! enabled)
{
busy = true;
// disabled - remove all usages
if (bootstrap == true)
{
if (logger.isDebugEnabled())
{
logger.debug("Disabled - clear usages for all users ...");
}
RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper();
// wrap to make the request in a transaction
RetryingTransactionCallback<Integer> clearAllUsages = new RetryingTransactionCallback<Integer>()
{
public Integer execute() throws Throwable
{
Set<NodeRef> allPeople = personService.getAllPeople();
for (NodeRef personNodeRef : allPeople)
{
nodeService.setProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT, null);
usageService.deleteDeltas(personNodeRef);
}
return allPeople.size();
}
};
// execute in txn
int count = txnHelper.doInTransaction(clearAllUsages, false);
if (logger.isDebugEnabled())
{
logger.debug("... cleared usages for " + count + " users");
}
}
}
else if (! busy && enabled)
{
busy = true;
if (bootstrap == true)
{
if (logger.isDebugEnabled())
{
logger.debug("Enabled - calculate missing usages ...");
}
RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper();
// wrap to make the request in a transaction
RetryingTransactionCallback<Set<String>> getAllPeople = new RetryingTransactionCallback<Set<String>>()
{
public Set<String> execute() throws Throwable
{
Set<NodeRef> allPeople = personService.getAllPeople();
Set<String> userNames = new HashSet<String>();
for (NodeRef personNodeRef : allPeople)
{
Long currentUsage = (Long)nodeService.getProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT);
if (currentUsage == null)
{
String userName = (String)nodeService.getProperty(personNodeRef, ContentModel.PROP_USERNAME);
userNames.add(userName);
}
}
return userNames;
}
};
// execute in READ-ONLY txn
final Set<String> userNames = txnHelper.doInTransaction(getAllPeople, true);
for (String userName : userNames)
{
recalculateUsage(userName);
}
if (logger.isDebugEnabled())
{
logger.debug("... calculated missing usages for " + userNames.size() + " users");
}
}
else
{
// Collapse usage deltas (if a person has initial usage set)
final RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper();
// wrap to make the request in a transaction and run as System user
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>()
{
public Object doWork() throws Exception
{
return txnHelper.doInTransaction(new RetryingTransactionCallback<Object>()
{
public Object execute() throws Throwable
{
// Get distinct candidates
Set<NodeRef> usageNodeRefs = usageService.getUsageDeltaNodes();
for(NodeRef usageNodeRef : usageNodeRefs)
{
QName nodeType = nodeService.getType(usageNodeRef);
if (nodeType.equals(ContentModel.TYPE_PERSON))
{
NodeRef personNodeRef = usageNodeRef;
String userName = (String)nodeService.getProperty(personNodeRef, ContentModel.PROP_USERNAME);
long currentUsage = contentUsageImpl.getUserStoredUsage(personNodeRef);
if (currentUsage != -1)
{
// collapse the usage deltas
currentUsage = contentUsageImpl.getUserUsage(userName);
usageService.deleteDeltas(personNodeRef);
contentUsageImpl.setUserStoredUsage(personNodeRef, currentUsage);
if (logger.isDebugEnabled())
{
logger.debug("Collapsed usage: username=" + userName + ", usage=" + currentUsage);
}
}
else
{
if (logger.isWarnEnabled())
{
logger.warn("Initial usage for user has not yet been calculated: " + userName);
}
}
}
}
return null;
}
});
}
}, AuthenticationUtil.getSystemUserName());
}
}
if (! busy)
{
try
{
busy = true;
// collapse usages - note: for MT environment, will collapse for all tenants
collapseUsages();
}
finally
{
busy = false;
}
}
}
finally
}
// called once on startup
public void bootstrap()
{
// default domain
bootstrapInternal();
if (tenantService.isEnabled())
{
List<Tenant> tenants = tenantDeployerService.getAllTenants();
for (Tenant tenant : tenants)
{
AuthenticationUtil.runAs(new RunAsWork<Object>()
{
public Object doWork() throws Exception
{
bootstrapInternal();
return null;
}
}, tenantService.getDomainUser(AuthenticationUtil.getSystemUserName(), tenant.getTenantDomain()));
}
}
}
public void bootstrapInternal()
{
if (! busy)
{
try
{
busy = true;
if (enabled)
{
// enabled - calculate missing usages
calculateMissingUsages();
}
else
{
// disabled - remove all usages
clearAllUsages();
}
}
finally
{
busy = false;
}
}
}
public void clearAllUsages()
{
if (logger.isDebugEnabled())
{
busy = false;
logger.debug("Disabled - clear usages for all users ...");
}
RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper();
// wrap to make the request in a transaction
RetryingTransactionCallback<Integer> clearAllUsages = new RetryingTransactionCallback<Integer>()
{
public Integer execute() throws Throwable
{
Set<NodeRef> allPeople = personService.getAllPeople();
for (NodeRef personNodeRef : allPeople)
{
nodeService.setProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT, null);
usageService.deleteDeltas(personNodeRef);
}
return allPeople.size();
}
};
// execute in txn
int count = txnHelper.doInTransaction(clearAllUsages, false);
if (logger.isDebugEnabled())
{
logger.debug("... cleared usages for " + count + " users");
}
}
public void calculateMissingUsages()
{
if (logger.isDebugEnabled())
{
logger.debug("Enabled - calculate missing usages ...");
}
RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper();
// wrap to make the request in a transaction
RetryingTransactionCallback<Set<String>> getAllPeople = new RetryingTransactionCallback<Set<String>>()
{
public Set<String> execute() throws Throwable
{
Set<NodeRef> allPeople = personService.getAllPeople();
Set<String> userNames = new HashSet<String>();
for (NodeRef personNodeRef : allPeople)
{
Long currentUsage = (Long)nodeService.getProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT);
if (currentUsage == null)
{
String userName = (String)nodeService.getProperty(personNodeRef, ContentModel.PROP_USERNAME);
userNames.add(userName);
}
}
return userNames;
}
};
// execute in READ-ONLY txn
final Set<String> userNames = txnHelper.doInTransaction(getAllPeople, true);
for (String userName : userNames)
{
recalculateUsage(userName);
}
if (logger.isDebugEnabled())
{
logger.debug("... calculated missing usages for " + userNames.size() + " users");
}
}
@@ -323,22 +327,81 @@ public class UserUsageTrackingComponent
// execute in READ-ONLY txn
final Long currentUsage = txnHelper.doInTransaction(calculatePersonCurrentUsage, true);
// wrap to make the request in a transaction and run as System user
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>()
// wrap to make the request in a transaction
RetryingTransactionCallback<Object> updatePersonCurrentUsage = new RetryingTransactionCallback<Object>()
{
public Object doWork() throws Exception
public Object execute() throws Throwable
{
return txnHelper.doInTransaction(new RetryingTransactionCallback<Object>()
{
public Object execute() throws Throwable
{
NodeRef personNodeRef = personService.getPerson(userName);
contentUsageImpl.setUserStoredUsage(personNodeRef, currentUsage);
usageService.deleteDeltas(personNodeRef);
return null;
}
});
NodeRef personNodeRef = personService.getPerson(userName);
contentUsageImpl.setUserStoredUsage(personNodeRef, currentUsage);
usageService.deleteDeltas(personNodeRef);
return null;
}
}, AuthenticationUtil.getSystemUserName());
};
// execute in txn
txnHelper.doInTransaction(updatePersonCurrentUsage, false);
}
/**
* Collapse usages - note: for MT environment, will collapse all tenants
*/
private void collapseUsages()
{
// Collapse usage deltas (if a person has initial usage set)
final RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper();
// wrap to make the request in a transaction
RetryingTransactionCallback<Object> collapseUsages = new RetryingTransactionCallback<Object>()
{
public Object execute() throws Throwable
{
// Get distinct candidates
Set<NodeRef> usageNodeRefs = usageService.getUsageDeltaNodes();
for(final NodeRef usageNodeRef : usageNodeRefs)
{
AuthenticationUtil.runAs(new RunAsWork<Object>()
{
public Object doWork() throws Exception
{
QName nodeType = nodeService.getType(usageNodeRef);
if (nodeType.equals(ContentModel.TYPE_PERSON))
{
NodeRef personNodeRef = usageNodeRef;
String userName = (String)nodeService.getProperty(personNodeRef, ContentModel.PROP_USERNAME);
long currentUsage = contentUsageImpl.getUserStoredUsage(personNodeRef);
if (currentUsage != -1)
{
// collapse the usage deltas
currentUsage = contentUsageImpl.getUserUsage(userName);
usageService.deleteDeltas(personNodeRef);
contentUsageImpl.setUserStoredUsage(personNodeRef, currentUsage);
if (logger.isDebugEnabled())
{
logger.debug("Collapsed usage: username=" + userName + ", usage=" + currentUsage);
}
}
else
{
if (logger.isWarnEnabled())
{
logger.warn("Initial usage for user has not yet been calculated: " + userName);
}
}
}
return null;
}
}, tenantService.getDomainUser(AuthenticationUtil.getSystemUserName(), tenantService.getDomain(usageNodeRef.getStoreRef().getIdentifier())));
}
return null;
}
};
// execute in txn
txnHelper.doInTransaction(collapseUsages, false);
}
}