mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
ACE-1447: Added 'cm:indexControl' aspect to surf-config folder and its children so they wouldn’t be indexed. Also added an asynchronous patch.
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@72733 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -1,3 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2014 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.alfresco.repo.admin.patch.impl;
|
||||
|
||||
|
@@ -0,0 +1,461 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2014 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.alfresco.repo.admin.patch.impl;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.admin.patch.AsynchronousPatch;
|
||||
import org.alfresco.repo.admin.patch.PatchExecuter;
|
||||
import org.alfresco.repo.batch.BatchProcessWorkProvider;
|
||||
import org.alfresco.repo.batch.BatchProcessor;
|
||||
import org.alfresco.repo.batch.BatchProcessor.BatchProcessWorker;
|
||||
import org.alfresco.repo.batch.BatchProcessor.BatchProcessWorkerAdaptor;
|
||||
import org.alfresco.repo.domain.node.NodeDAO;
|
||||
import org.alfresco.repo.domain.patch.PatchDAO;
|
||||
import org.alfresco.repo.domain.qname.QNameDAO;
|
||||
import org.alfresco.repo.policy.BehaviourFilter;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.site.SiteModel;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.rule.RuleService;
|
||||
import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.extensions.surf.util.I18NUtil;
|
||||
|
||||
/**
|
||||
* Patch to add <i>cm:indexControl</i> aspect to sites' surf-config folders and
|
||||
* their children as well as to the shared surf-config folder(s) and its/their children.
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
*/
|
||||
public class SurfConfigFolderPatch extends AsynchronousPatch
|
||||
{
|
||||
private static final Log logger = LogFactory.getLog(SurfConfigFolderPatch.class);
|
||||
private static final Log progress_logger = LogFactory.getLog(PatchExecuter.class);
|
||||
|
||||
private static final String MSG_SUCCESS = "patch.surfConfigFolderPatch.result";
|
||||
|
||||
// name of the surf config folder
|
||||
private static final String SURF_CONFIG = "surf-config";
|
||||
private static final String COMPONENTS = "components"; // cm:surf-config/cm:components
|
||||
private static final String PAGES = "pages"; // cm:surf-config/cm:pages
|
||||
private static final String SITE = "site"; // cm:surf-config/cm:pages/cm:site
|
||||
|
||||
private static final int SITE_BATCH_THREADS = 2;
|
||||
private static final int SHARED_SURF_CONFIG_BATCH_THREADS = 2;
|
||||
private static final int BATCH_SIZE = 1000;
|
||||
private static final int SHARED_SURF_CONFIG_BATCH_MAX_QUERY_RANGE = 1000;
|
||||
private static final int SITE_BATCH_MAX_QUERY_RANGE = 1000;
|
||||
|
||||
private PatchDAO patchDAO;
|
||||
private NodeDAO nodeDAO;
|
||||
private QNameDAO qnameDAO;
|
||||
private BehaviourFilter behaviourFilter;
|
||||
private RuleService ruleService;
|
||||
|
||||
/**
|
||||
* @param patchDAO the patchDAO to set
|
||||
*/
|
||||
public void setPatchDAO(PatchDAO patchDAO)
|
||||
{
|
||||
this.patchDAO = patchDAO;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nodeDAO the nodeDAO to set
|
||||
*/
|
||||
public void setNodeDAO(NodeDAO nodeDAO)
|
||||
{
|
||||
this.nodeDAO = nodeDAO;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param qnameDAO the qnameDAO to set
|
||||
*/
|
||||
public void setQnameDAO(QNameDAO qnameDAO)
|
||||
{
|
||||
this.qnameDAO = qnameDAO;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param behaviourFilter the behaviourFilter to set
|
||||
*/
|
||||
public void setBehaviourFilter(BehaviourFilter behaviourFilter)
|
||||
{
|
||||
this.behaviourFilter = behaviourFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ruleService the ruleService to set
|
||||
*/
|
||||
public void setRuleService(RuleService ruleService)
|
||||
{
|
||||
this.ruleService = ruleService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkProperties()
|
||||
{
|
||||
super.checkProperties();
|
||||
checkPropertyNotNull(patchDAO, "patchDAO");
|
||||
checkPropertyNotNull(nodeDAO, "nodeDAO");
|
||||
checkPropertyNotNull(qnameDAO, "qnameDAO");
|
||||
checkPropertyNotNull(ruleService, "ruleService");
|
||||
checkPropertyNotNull(behaviourFilter, "behaviourFilter");
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.admin.patch.AbstractPatch#applyInternal()
|
||||
*/
|
||||
@Override
|
||||
protected String applyInternal() throws Exception
|
||||
{
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
// get user names that will be used within RunAs
|
||||
final String systemUser = AuthenticationUtil.getSystemUserName();
|
||||
|
||||
// Instance to provide raw data to process
|
||||
BatchProcessWorkProvider<Long> siteWorkProvider = new SiteWorkProvider();
|
||||
|
||||
// Instance to handle each item of work
|
||||
BatchProcessWorker<Long> siteWorker = new BatchProcessWorkerAdaptor<Long>()
|
||||
{
|
||||
@Override
|
||||
public void beforeProcess() throws Throwable
|
||||
{
|
||||
// Run as the systemuser
|
||||
AuthenticationUtil.setRunAsUser(systemUser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(Long entry) throws Throwable
|
||||
{
|
||||
// Disable auditable aspect
|
||||
behaviourFilter.disableBehaviour();
|
||||
// Disable rules
|
||||
ruleService.disableRules();
|
||||
try
|
||||
{
|
||||
SurfConfigFolderPatch.this.process(entry);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ruleService.enableRules();
|
||||
behaviourFilter.enableBehaviour();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterProcess() throws Throwable
|
||||
{
|
||||
AuthenticationUtil.clearCurrentSecurityContext();
|
||||
}
|
||||
};
|
||||
|
||||
BatchProcessor<Long> siteBatchProcessor = new BatchProcessor<Long>("SurfConfigFolderPatch",
|
||||
transactionService.getRetryingTransactionHelper(), siteWorkProvider, SITE_BATCH_THREADS, BATCH_SIZE, null,
|
||||
progress_logger, 1000);
|
||||
|
||||
int updatedSiteSurfConfig = siteBatchProcessor.process(siteWorker, true);
|
||||
|
||||
// shared surf-config folder
|
||||
// Instance to provide raw data to process
|
||||
BatchProcessWorkProvider<NodeRef> surfConfigWorkProvider = new SharedSurfConfigWorkProvider();
|
||||
|
||||
// Instance to handle each item of work
|
||||
BatchProcessWorker<NodeRef> surfConfigWorker = new BatchProcessWorkerAdaptor<NodeRef>()
|
||||
{
|
||||
@Override
|
||||
public void beforeProcess() throws Throwable
|
||||
{
|
||||
// Run as the systemuser
|
||||
AuthenticationUtil.setRunAsUser(systemUser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(NodeRef entry) throws Throwable
|
||||
{
|
||||
// Disable auditable aspect
|
||||
behaviourFilter.disableBehaviour();
|
||||
// Disable rules
|
||||
ruleService.disableRules();
|
||||
try
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("\tP: Processing [company_home/sites/surf-config/pages/user] children");
|
||||
}
|
||||
// add aspect to
|
||||
// app:company_home/st:sites/cm:surf-config/cm:pages/cm:user/{userName}
|
||||
addIndexControlAspectIfNotExist(entry);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ruleService.enableRules();
|
||||
behaviourFilter.enableBehaviour();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterProcess() throws Throwable
|
||||
{
|
||||
AuthenticationUtil.clearCurrentSecurityContext();
|
||||
}
|
||||
};
|
||||
|
||||
BatchProcessor<NodeRef> surfConfigBatchProcessor = new BatchProcessor<NodeRef>("SurfConfigFolderPatch",
|
||||
transactionService.getRetryingTransactionHelper(), surfConfigWorkProvider, SHARED_SURF_CONFIG_BATCH_THREADS,
|
||||
BATCH_SIZE, null, progress_logger, 1000);
|
||||
|
||||
surfConfigBatchProcessor.process(surfConfigWorker, true);
|
||||
|
||||
int numOfSites = updatedSiteSurfConfig / 12;
|
||||
String msg = I18NUtil.getMessage(MSG_SUCCESS, numOfSites);
|
||||
|
||||
long end = System.currentTimeMillis();
|
||||
logger.info(msg + " in [" + (end - start) + " ms]");
|
||||
return msg;
|
||||
}
|
||||
|
||||
private void process(long siteId)
|
||||
{
|
||||
String siteName = (String) nodeDAO.getNodeProperty(siteId, ContentModel.PROP_NAME);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("\tP: Processing surf-config folder for the site: [" + siteName + ']');
|
||||
}
|
||||
|
||||
// {siteName}/cm:surf-config/
|
||||
Pair<Long, ChildAssociationRef> surfConfigPair = nodeDAO.getChildAssoc(siteId, ContentModel.ASSOC_CONTAINS, SURF_CONFIG);
|
||||
|
||||
if (surfConfigPair == null)
|
||||
{
|
||||
logger.info("WARNING: unable to find surf-config folder for site: [" + siteName + ']');
|
||||
return;
|
||||
}
|
||||
NodeRef surfConfigNodeRef = surfConfigPair.getSecond().getChildRef();
|
||||
// apply the aspect to suef-config folder
|
||||
addIndexControlAspectIfNotExist(surfConfigNodeRef);
|
||||
|
||||
// cm:surf-config/cm:components
|
||||
NodeRef componentsNodeRef = nodeService.getChildByName(surfConfigNodeRef, ContentModel.ASSOC_CONTAINS, COMPONENTS);
|
||||
if (componentsNodeRef != null)
|
||||
{
|
||||
// {siteName}/cm:surf-config/cm:components nodeRef
|
||||
addIndexControlAspectIfNotExist(componentsNodeRef);
|
||||
|
||||
List<ChildAssociationRef> listOfComponents = nodeService.getChildAssocs(componentsNodeRef,
|
||||
ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL);
|
||||
// apply the aspect to all of the children (6 in total)
|
||||
for (ChildAssociationRef comp : listOfComponents)
|
||||
{
|
||||
addIndexControlAspectIfNotExist(comp.getChildRef());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.info("WARNING: unable to find surf-config/components folder for site: [" + siteName + ']');
|
||||
}
|
||||
|
||||
// cm:surf-config/cm:pages folder
|
||||
NodeRef pagesNodeRef = nodeService.getChildByName(surfConfigNodeRef, ContentModel.ASSOC_CONTAINS, PAGES);
|
||||
if (pagesNodeRef == null)
|
||||
{
|
||||
logger.info("WARNING: unable to find surf-config/pages folder for site: [" + siteName + ']');
|
||||
return;
|
||||
}
|
||||
// add aspect to cm:pages
|
||||
addIndexControlAspectIfNotExist(pagesNodeRef);
|
||||
|
||||
// cm:surf-config/cm:pages/cm:site folder
|
||||
NodeRef siteNodeRef = nodeService.getChildByName(pagesNodeRef, ContentModel.ASSOC_CONTAINS, SITE);
|
||||
if (siteNodeRef == null)
|
||||
{
|
||||
logger.info("WARNING: unable to find surf-config/pages/site folder for site: [" + siteName + ']');
|
||||
return;
|
||||
}
|
||||
// add aspect to cm:pages/cm:site folder
|
||||
addIndexControlAspectIfNotExist(siteNodeRef);
|
||||
|
||||
// cm:surf-config/cm:pages/cm:site/{siteName}
|
||||
NodeRef siteChildNodeRef = nodeService.getChildByName(siteNodeRef, ContentModel.ASSOC_CONTAINS, siteName);
|
||||
|
||||
if (siteChildNodeRef == null)
|
||||
{
|
||||
logger.info("WARNING: unable to find surf-config/pages/site/" + siteName + " folder for site: [" + siteName + ']');
|
||||
return;
|
||||
}
|
||||
// add aspect to cm:surf-config/cm:pages/cm:site/{siteName}
|
||||
addIndexControlAspectIfNotExist(siteChildNodeRef);
|
||||
|
||||
List<ChildAssociationRef> listOfComponents = nodeService.getChildAssocs(siteChildNodeRef, ContentModel.ASSOC_CONTAINS,
|
||||
RegexQNamePattern.MATCH_ALL);
|
||||
// apply the aspect to all of the children
|
||||
for (ChildAssociationRef comp : listOfComponents)
|
||||
{
|
||||
addIndexControlAspectIfNotExist(comp.getChildRef());
|
||||
}
|
||||
}
|
||||
|
||||
private void addIndexControlAspectIfNotExist(NodeRef nodeRef)
|
||||
{
|
||||
// We need to check the property rather than the aspect, as the node
|
||||
// might have the aspect but not the correct property.
|
||||
Serializable indexProp = nodeService.getProperty(nodeRef, ContentModel.PROP_IS_INDEXED);
|
||||
if (indexProp == null || ((Boolean) indexProp))
|
||||
{
|
||||
nodeService.addAspect(nodeRef, ContentModel.ASPECT_INDEX_CONTROL,
|
||||
Collections.singletonMap(ContentModel.PROP_IS_INDEXED, (Serializable) false));
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("\tP: Adding cm:indexControl aspect to node: [" + nodeRef + ']');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Work provider which performs incremental queries to find site nodes.
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
*/
|
||||
private class SiteWorkProvider implements BatchProcessWorkProvider<Long>
|
||||
{
|
||||
private long maxId = Long.MAX_VALUE;
|
||||
private long workCount = Long.MAX_VALUE;
|
||||
private long currentId = 0L;
|
||||
private final long siteTypeQNameId;
|
||||
|
||||
private SiteWorkProvider()
|
||||
{
|
||||
this.siteTypeQNameId = qnameDAO.getQName(SiteModel.TYPE_SITE).getFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int getTotalEstimatedWorkSize()
|
||||
{
|
||||
if (maxId == Long.MAX_VALUE)
|
||||
{
|
||||
maxId = patchDAO.getMaxAdmNodeID();
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("\tQ: Max node id: " + maxId);
|
||||
}
|
||||
}
|
||||
if (workCount == Long.MAX_VALUE)
|
||||
{
|
||||
// get the sites count
|
||||
workCount = patchDAO.getCountNodesWithTypId(SiteModel.TYPE_SITE);
|
||||
// Each site has 12 children (we care only about surf-config
|
||||
// itself and its children)
|
||||
workCount *= 12;
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("\tQ: Work count: " + workCount);
|
||||
}
|
||||
}
|
||||
return (int) workCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Collection<Long> getNextWork()
|
||||
{
|
||||
// Record the site node IDs
|
||||
final List<Long> siteNodeIDs = new ArrayList<Long>(SITE_BATCH_MAX_QUERY_RANGE);
|
||||
|
||||
// Keep querying until we have enough results to give back
|
||||
int minResults = SITE_BATCH_MAX_QUERY_RANGE / 2;
|
||||
while (currentId <= maxId && siteNodeIDs.size() < minResults)
|
||||
{
|
||||
List<Long> nodeIds = patchDAO.getNodesByTypeQNameId(siteTypeQNameId, currentId, currentId
|
||||
+ SITE_BATCH_MAX_QUERY_RANGE);
|
||||
siteNodeIDs.addAll(nodeIds);
|
||||
// Increment the minimum ID
|
||||
currentId += SITE_BATCH_MAX_QUERY_RANGE;
|
||||
}
|
||||
// Done
|
||||
return siteNodeIDs;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Work provider which performs incremental queries to find shared
|
||||
* Surf-Config folders and their children.
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
*/
|
||||
private class SharedSurfConfigWorkProvider implements BatchProcessWorkProvider<NodeRef>
|
||||
{
|
||||
private long maxId = Long.MAX_VALUE;
|
||||
private long currentId = 0L;
|
||||
|
||||
private SharedSurfConfigWorkProvider()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int getTotalEstimatedWorkSize()
|
||||
{
|
||||
if (maxId == Long.MAX_VALUE)
|
||||
{
|
||||
maxId = patchDAO.getMaxAdmNodeID();
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("\tQ: Max node id: " + maxId);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Collection<NodeRef> getNextWork()
|
||||
{
|
||||
// Record the user folder node IDs
|
||||
final List<NodeRef> folderNodes = new ArrayList<NodeRef>(SHARED_SURF_CONFIG_BATCH_MAX_QUERY_RANGE);
|
||||
|
||||
// Keep querying until we have enough results to give back
|
||||
int minResults = SHARED_SURF_CONFIG_BATCH_MAX_QUERY_RANGE / 2;
|
||||
while (currentId <= maxId && folderNodes.size() < minResults)
|
||||
{
|
||||
|
||||
List<NodeRef> nodeIds = patchDAO.getChildrenOfTheSharedSurfConfigFolder(currentId, currentId
|
||||
+ SHARED_SURF_CONFIG_BATCH_MAX_QUERY_RANGE);
|
||||
folderNodes.addAll(nodeIds);
|
||||
// Increment the minimum ID
|
||||
currentId += SHARED_SURF_CONFIG_BATCH_MAX_QUERY_RANGE;
|
||||
}
|
||||
// Preload the nodes for quicker access
|
||||
nodeDAO.cacheNodes(folderNodes);
|
||||
// Done
|
||||
return folderNodes;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user