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:
Derek Hulley
2010-03-11 15:08:37 +00:00
parent 0c5d02d543
commit c36fe6b6c0
6 changed files with 200 additions and 24 deletions

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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)
{

View File

@@ -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);

View File

@@ -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

View File

@@ -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);
}
}