mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Merged BRANCHES/V3.2 to HEAD:
18104: Merged in DEV/BELARUS/V3.2-2009_12_15 rev 17847: ETHREEOH-3746 DB2 upgrade issue 18476: Fixed ETHREEOH-3983: NodeLockedException: IncompleteNodeTagger fails for locked nodes 18761: Merged V3.1 to V3.2 18760 (RECORD-ONLY): Merged V2.2 to V3.1 18759: Merged DEV/BELARUS/V2.2-2010_02_03 to V2.2 18553: ResultSet closing was added to methods. This was fixed separately in V3.2. 18787: MT: fix ETHREEOH-4125 - authority migration / batch processor (when upgrading groups from 3.1 to 3.2) 19059: Fix read-only marker in test 19061: Handle missing alf_content_data ID for node cleaning git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@19226 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -36,7 +36,9 @@ import org.alfresco.repo.admin.patch.AbstractPatch;
|
||||
import org.alfresco.repo.admin.patch.PatchExecuter;
|
||||
import org.alfresco.repo.batch.BatchProcessor;
|
||||
import org.alfresco.repo.importer.ImporterBootstrap;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authority.UnknownAuthorityException;
|
||||
import org.alfresco.repo.tenant.TenantService;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||
@@ -186,11 +188,29 @@ public class AuthorityMigrationPatch extends AbstractPatch implements Applicatio
|
||||
.getProperty(current, AuthorityMigrationPatch.PROP_MEMBERS));
|
||||
if (members != null)
|
||||
{
|
||||
String tenantDomain = null;
|
||||
if (tenantAdminService.isEnabled())
|
||||
{
|
||||
tenantDomain = tenantAdminService.getCurrentUserDomain();
|
||||
}
|
||||
|
||||
for (String user : members)
|
||||
{
|
||||
// Believe it or not, some old authorities have null members in them!
|
||||
if (user != null)
|
||||
{
|
||||
if ((tenantDomain != null) && (! (tenantDomain.equals(TenantService.DEFAULT_DOMAIN))))
|
||||
{
|
||||
if (tenantAdminService.getUserDomain(user).equals(TenantService.DEFAULT_DOMAIN))
|
||||
{
|
||||
if (user.equals(tenantAdminService.getBaseNameUser(AuthenticationUtil.getAdminUserName())))
|
||||
{
|
||||
// MT: workaround for CHK-11393 (eg. EMAIL_CONTRIBUTORS with member "admin" instead of "admin@tenant")
|
||||
user = tenantAdminService.getDomainUser(user, tenantDomain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Set<String> propParents = parentAssocs.get(user);
|
||||
if (propParents == null)
|
||||
{
|
||||
@@ -271,7 +291,7 @@ public class AuthorityMigrationPatch extends AbstractPatch implements Applicatio
|
||||
};
|
||||
// Migrate using 2 threads, 20 authorities per transaction. Log every 100 entries.
|
||||
new BatchProcessor<Map.Entry<String, Set<String>>>(AuthorityMigrationPatch.progress_logger,
|
||||
this.transactionService.getRetryingTransactionHelper(), this.ruleService,
|
||||
this.transactionService.getRetryingTransactionHelper(), this.ruleService, this.tenantAdminService,
|
||||
this.applicationEventPublisher, parentAssocs.entrySet(), I18NUtil
|
||||
.getMessage(AuthorityMigrationPatch.MSG_PROCESS_NAME), 100, 2, 20).process(worker, true);
|
||||
}
|
||||
|
@@ -181,7 +181,7 @@ public class FixNameCrcValuesPatch extends AbstractPatch implements ApplicationE
|
||||
{
|
||||
// get the association types to check
|
||||
BatchProcessor<Long> batchProcessor = new BatchProcessor<Long>(logger, transactionService
|
||||
.getRetryingTransactionHelper(), ruleService, applicationEventPublisher, findMismatchedCrcs(),
|
||||
.getRetryingTransactionHelper(), ruleService, tenantAdminService, applicationEventPublisher, findMismatchedCrcs(),
|
||||
"FixNameCrcValuesPatch", 1000, 2, 20);
|
||||
|
||||
// Precautionary flush and clear so that we have an empty session
|
||||
|
@@ -34,6 +34,10 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.repo.tenant.TenantService;
|
||||
import org.alfresco.repo.tenant.TenantUserService;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.transaction.TransactionListenerAdapter;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
@@ -64,6 +68,11 @@ public class BatchProcessor<T> implements BatchMonitor
|
||||
/** The rule service. */
|
||||
private final RuleService ruleService;
|
||||
|
||||
/** The tenant user service. */
|
||||
private final TenantUserService tenantUserService;
|
||||
|
||||
private final String tenantDomain;
|
||||
|
||||
/** The collection. */
|
||||
private final Collection<T> collection;
|
||||
|
||||
@@ -128,15 +137,58 @@ public class BatchProcessor<T> implements BatchMonitor
|
||||
public BatchProcessor(Log logger, RetryingTransactionHelper retryingTransactionHelper, RuleService ruleService,
|
||||
ApplicationEventPublisher applicationEventPublisher, Collection<T> collection, String processName,
|
||||
int loggingInterval, int workerThreads, int batchSize)
|
||||
{
|
||||
this(logger, retryingTransactionHelper, ruleService, null, applicationEventPublisher, collection, processName,
|
||||
loggingInterval, workerThreads, batchSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new batch processor.
|
||||
*
|
||||
* @param logger
|
||||
* the logger to use
|
||||
* @param retryingTransactionHelper
|
||||
* the retrying transaction helper
|
||||
* @param ruleService
|
||||
* the rule service
|
||||
* @param tenantUserService
|
||||
* the tenant user service
|
||||
* @param collection
|
||||
* the collection
|
||||
* @param processName
|
||||
* the process name
|
||||
* @param loggingInterval
|
||||
* the number of entries to process before reporting progress
|
||||
* @param applicationEventPublisher
|
||||
* the application event publisher
|
||||
* @param workerThreads
|
||||
* the number of worker threads
|
||||
* @param batchSize
|
||||
* the number of entries we process at a time in a transaction
|
||||
*/
|
||||
public BatchProcessor(Log logger, RetryingTransactionHelper retryingTransactionHelper, RuleService ruleService,
|
||||
TenantUserService tenantUserService, ApplicationEventPublisher applicationEventPublisher, Collection<T> collection, String processName,
|
||||
int loggingInterval, int workerThreads, int batchSize)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.retryingTransactionHelper = retryingTransactionHelper;
|
||||
this.ruleService = ruleService;
|
||||
this.tenantUserService = tenantUserService;
|
||||
this.collection = collection;
|
||||
this.processName = processName;
|
||||
this.loggingInterval = loggingInterval;
|
||||
this.workerThreads = workerThreads;
|
||||
this.batchSize = batchSize;
|
||||
|
||||
if (tenantUserService != null)
|
||||
{
|
||||
this.tenantDomain = tenantUserService.getUserDomain(AuthenticationUtil.getRunAsUser());
|
||||
}
|
||||
else
|
||||
{
|
||||
this.tenantDomain = TenantService.DEFAULT_DOMAIN;
|
||||
}
|
||||
|
||||
// Let the (enterprise) monitoring side know of our presence
|
||||
applicationEventPublisher.publishEvent(new BatchMonitorEvent(this));
|
||||
}
|
||||
@@ -313,6 +365,7 @@ public class BatchProcessor<T> implements BatchMonitor
|
||||
{
|
||||
batch = new ArrayList<T>(this.batchSize);
|
||||
}
|
||||
|
||||
if (executorService == null)
|
||||
{
|
||||
callback.run();
|
||||
@@ -551,9 +604,24 @@ public class BatchProcessor<T> implements BatchMonitor
|
||||
{
|
||||
// Disable rules for this thread
|
||||
BatchProcessor.this.ruleService.disableRules();
|
||||
|
||||
final BatchProcessor<T>.TxnCallback callback = this;
|
||||
try
|
||||
{
|
||||
BatchProcessor.this.retryingTransactionHelper.doInTransaction(this, false, this.splitTxns);
|
||||
String systemUser = AuthenticationUtil.getSystemUserName();
|
||||
if (tenantUserService != null)
|
||||
{
|
||||
systemUser = tenantUserService.getDomainUser(AuthenticationUtil.getSystemUserName(), tenantDomain);
|
||||
}
|
||||
|
||||
AuthenticationUtil.runAs(new RunAsWork<Void>()
|
||||
{
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
BatchProcessor.this.retryingTransactionHelper.doInTransaction(callback, false, splitTxns);
|
||||
return null;
|
||||
}
|
||||
}, systemUser);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
|
@@ -26,6 +26,8 @@ import java.util.Set;
|
||||
import org.alfresco.repo.domain.contentdata.AbstractContentDataDAOImpl;
|
||||
import org.alfresco.repo.domain.contentdata.ContentDataEntity;
|
||||
import org.alfresco.repo.domain.contentdata.ContentUrlEntity;
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.orm.ibatis.SqlMapClientTemplate;
|
||||
|
||||
import com.ibatis.sqlmap.client.event.RowHandler;
|
||||
@@ -202,18 +204,20 @@ public class ContentDataDAOImpl extends AbstractContentDataDAOImpl
|
||||
protected int deleteContentDataEntity(Long id)
|
||||
{
|
||||
// Get the content urls
|
||||
ContentDataEntity contentDataEntity = getContentDataEntity(id);
|
||||
// This might be null as there is no constraint ensuring that the node points to a valid ContentData entity
|
||||
if (contentDataEntity != null)
|
||||
try
|
||||
{
|
||||
// Register the content URL for a later orphan-check
|
||||
String contentUrl = contentDataEntity.getContentUrl();
|
||||
ContentData contentData = getContentData(id).getSecond();
|
||||
String contentUrl = contentData.getContentUrl();
|
||||
if (contentUrl != null)
|
||||
{
|
||||
// It has been dereferenced and may be orphaned - we'll check later
|
||||
registerDereferencedContentUrl(contentUrl);
|
||||
}
|
||||
}
|
||||
catch (DataIntegrityViolationException e)
|
||||
{
|
||||
// Doesn't exist. The node doesn't enforce a FK constraint, so we protect against this.
|
||||
}
|
||||
// Issue the delete statement
|
||||
Map<String, Object> params = new HashMap<String, Object>(11);
|
||||
params.put("id", id);
|
||||
|
@@ -32,6 +32,8 @@ import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.node.NodeServicePolicies;
|
||||
import org.alfresco.repo.policy.JavaBehaviour;
|
||||
import org.alfresco.repo.policy.PolicyComponent;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
||||
import org.alfresco.repo.transaction.TransactionListenerAdapter;
|
||||
import org.alfresco.service.cmr.dictionary.AspectDefinition;
|
||||
@@ -359,11 +361,22 @@ public class IncompleteNodeTagger
|
||||
@Override
|
||||
public void beforeCommit(boolean readOnly)
|
||||
{
|
||||
Map<NodeRef, Set<QName>> nodes = getNodes();
|
||||
final Map<NodeRef, Set<QName>> nodes = getNodes();
|
||||
if (readOnly || nodes == null)
|
||||
{
|
||||
// Nothing was touched
|
||||
return;
|
||||
}
|
||||
// clear the set out of the transaction
|
||||
// there may be processes that react to the addition/removal of the aspect,
|
||||
// and these will, in turn, lead to further events
|
||||
AlfrescoTransactionSupport.unbindResource(KEY_NODES);
|
||||
|
||||
// Tag/untag the nodes as 'system' to prevent cm:lockable-related issues (ETHREEOH-3983)
|
||||
RunAsWork<Void> processNodesWork = new RunAsWork<Void>()
|
||||
{
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
// process each node
|
||||
for (Map.Entry<NodeRef, Set<QName>> entry : nodes.entrySet())
|
||||
{
|
||||
@@ -372,12 +385,17 @@ public class IncompleteNodeTagger
|
||||
processNode(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
AuthenticationUtil.runAs(processNodesWork, AuthenticationUtil.getSystemUserName());
|
||||
}
|
||||
|
||||
private void processNode(NodeRef nodeRef, Set<QName> assocTypes)
|
||||
{
|
||||
// ignore the node if the marker aspect is already present
|
||||
boolean isTagged = nodeService.hasAspect(nodeRef, ContentModel.ASPECT_INCOMPLETE);
|
||||
// get the node aspects
|
||||
Set<QName> aspectTypeQNames = nodeService.getAspects(nodeRef);
|
||||
boolean isTagged = aspectTypeQNames.contains(ContentModel.ASPECT_INCOMPLETE);
|
||||
|
||||
// get the node properties
|
||||
Map<QName, Serializable> nodeProperties = nodeService.getProperties(nodeRef);
|
||||
@@ -401,8 +419,6 @@ public class IncompleteNodeTagger
|
||||
return;
|
||||
}
|
||||
|
||||
// get the node aspects
|
||||
Set<QName> aspectTypeQNames = nodeService.getAspects(nodeRef);
|
||||
for (QName aspectTypeQName : aspectTypeQNames)
|
||||
{
|
||||
// get property definitions for the aspect
|
||||
|
@@ -25,14 +25,22 @@ import javax.transaction.UserTransaction;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.avm.util.HrefBearingRequestPathNameMatcher;
|
||||
import org.alfresco.repo.dictionary.DictionaryDAO;
|
||||
import org.alfresco.repo.dictionary.M2Model;
|
||||
import org.alfresco.repo.node.BaseNodeServiceTest;
|
||||
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.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.lock.LockService;
|
||||
import org.alfresco.service.cmr.lock.LockType;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.security.AuthenticationService;
|
||||
import org.alfresco.service.cmr.security.MutableAuthenticationService;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.PropertyMap;
|
||||
@@ -56,6 +64,8 @@ public class IncompleteNodeTaggerTest extends TestCase
|
||||
private PropertyMap properties;
|
||||
private UserTransaction txn;
|
||||
private AuthenticationComponent authenticationComponent;
|
||||
private MutableAuthenticationService authenticationService;
|
||||
private PermissionService permissionService;
|
||||
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
@@ -71,10 +81,18 @@ public class IncompleteNodeTaggerTest extends TestCase
|
||||
|
||||
serviceRegistry = (ServiceRegistry) IntegrityTest.ctx.getBean(ServiceRegistry.SERVICE_REGISTRY);
|
||||
nodeService = serviceRegistry.getNodeService();
|
||||
authenticationService = serviceRegistry.getAuthenticationService();
|
||||
permissionService = serviceRegistry.getPermissionService();
|
||||
this.authenticationComponent = (AuthenticationComponent)IntegrityTest.ctx.getBean("authenticationComponent");
|
||||
|
||||
this.authenticationComponent.setSystemUserAsCurrentUser();
|
||||
|
||||
String user = getName();
|
||||
if (!authenticationService.authenticationExists(user))
|
||||
{
|
||||
authenticationService.createAuthentication(user, user.toCharArray());
|
||||
}
|
||||
|
||||
// begin a transaction
|
||||
TransactionService transactionService = serviceRegistry.getTransactionService();
|
||||
txn = transactionService.getUserTransaction();
|
||||
@@ -83,11 +101,20 @@ public class IncompleteNodeTaggerTest extends TestCase
|
||||
if (!nodeService.exists(storeRef))
|
||||
{
|
||||
nodeService.createStore(storeRef.getProtocol(), storeRef.getIdentifier());
|
||||
}
|
||||
rootNodeRef = nodeService.getRootNode(storeRef);
|
||||
// Make sure our user can do everything
|
||||
permissionService.setPermission(rootNodeRef, user, PermissionService.ALL_PERMISSIONS, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
rootNodeRef = nodeService.getRootNode(storeRef);
|
||||
}
|
||||
|
||||
properties = new PropertyMap();
|
||||
properties.put(IntegrityTest.TEST_PROP_TEXT_C, "abc");
|
||||
|
||||
// Authenticate as a test-specific user
|
||||
authenticationComponent.setCurrentUser(user);
|
||||
}
|
||||
|
||||
public void tearDown() throws Exception
|
||||
@@ -115,10 +142,18 @@ public class IncompleteNodeTaggerTest extends TestCase
|
||||
assertNotNull("IncompleteNodeTagger not created", tagger);
|
||||
}
|
||||
|
||||
private void checkTagging(NodeRef nodeRef, boolean mustBeTagged)
|
||||
private void checkTagging(final NodeRef nodeRef, final boolean mustBeTagged)
|
||||
{
|
||||
tagger.beforeCommit(false);
|
||||
RunAsWork<Void> checkWork = new RunAsWork<Void>()
|
||||
{
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
assertEquals(nodeService.hasAspect(nodeRef, ContentModel.ASPECT_INCOMPLETE), mustBeTagged);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
AuthenticationUtil.runAs(checkWork, AuthenticationUtil.getSystemUserName());
|
||||
}
|
||||
|
||||
public void testCreateWithoutProperties() throws Exception
|
||||
@@ -150,4 +185,37 @@ public class IncompleteNodeTaggerTest extends TestCase
|
||||
);
|
||||
checkTagging(nodeRef, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* <a href="http://issues.alfresco.com/jira/browse/ETHREEOH-3983">ETHREEOH-3983</a>
|
||||
*/
|
||||
public void testIncompleteLockedNode() throws Exception
|
||||
{
|
||||
LockService lockService = serviceRegistry.getLockService();
|
||||
|
||||
NodeRef nodeRef = createNode("abc", IntegrityTest.TEST_TYPE_WITH_PROPERTIES, null);
|
||||
checkTagging(nodeRef, true);
|
||||
// Now remove the aspect, lock the node and check again
|
||||
nodeService.removeAspect(nodeRef, ContentModel.ASPECT_INCOMPLETE);
|
||||
lockService.lock(nodeRef, LockType.READ_ONLY_LOCK);
|
||||
|
||||
// Authenticate as someone else - someone not able to do anything
|
||||
final String user = "someuser";
|
||||
RunAsWork<Void> createUserWork = new RunAsWork<Void>()
|
||||
{
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
if (!authenticationService.authenticationExists(user))
|
||||
{
|
||||
authenticationService.createAuthentication(user, user.toCharArray());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
AuthenticationUtil.runAs(createUserWork, AuthenticationUtil.getSystemUserName());
|
||||
authenticationComponent.setCurrentUser(user);
|
||||
|
||||
// Tag
|
||||
checkTagging(nodeRef, true);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user