mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Merged V3.2 to HEAD
15897: Merged V3.1 to V3.2 14485: (RECORD ONLY) ETHREEOH-1937 14915: (RECORD ONLY) Fix for ETHREEOH-2011: chaining-authentication-context.xml.sample 14954: (RECORD ONLY) Fix merge error 14966: (RECORD ONLY) Merged V2.2 to V3.1 14131: *RECORD ONLY* 14605: Merged HEAD to V2.2 (workaround for ETWOTWO-1137) 14368: Fix for ETHREEOH-1936 14607: Fixed NPE in TextMiningContentTransformer: Lead-up to fix for ETWOTWO-1174 14992: (RECORD ONLY) Updated svn:mergeinfo for V2.1-A 15080: Applied suggested fix for ETHREEOH-2252: Emailed content created in wrong space 15131: Merged V2.1-A to V3.1 (ETHREEOH-2270) 13465: Fix for ADB-161 ACT 7870 - added 'xsd' to mimetype map. 15134: Merged V2.2 to V3.1 14332: (RECORD-ONLY) 14717: (RECORD-ONLY) 14745: (RECORD-ONLY) 14746: Fixed error relating to detection and clean-up of duplicate child associations 14759: Missed check-in: Set transactionService for post-transaction duplicate child assoc cleanup 14761: (RECORD-ONLY) 14885: (RECORD-ONLY) 14893: (RECORD-ONLY) 14903: (RECORD-ONLY) 15204: Fixed ETHREEOH-2303: FixNameCrcValuesPatch throws ConstraintViolationException during upgrade ... 15214: Fixed ETHREEOH-1861: Offline synchronization updates file content without any changes 15271: Applied patch fix: Imported users don't conform to case-sensitivity switch 15352: ETHREEOH-2322 15361: ETHREEOH-1112 15369: ETHREEOH-2448 15419: ETHREEOH-2479 15431: ETHREEOH-2520 and ETHREEOH-2521 15587: (RECORD ONLY) Moved Enterprise-only scripts to correct location 15616: Fix ETHREEOH-2581 - WCM layered folder - can't submit deleted file 15675: WCM fixes (ETHREEOH-2110 & ETHREEOH-2645) 15836: Check for null username in ContentUsage service getUserUsage() method 15840: (RECORD ONLY) Merged V3.2 to V3.1 14760: Fix for ALFCOM-586 - trims and ignores leading/trailing whitespace before validation in JSF client forms. 15841: Fixes for ETHREEOH-2702 and ETHREEOH-2687 15860: (RECORD ONLY) Added Oracle and MS SQL Server config 15891: Removed unused compiler directive ___________________________________________________________________ Modified: svn:mergeinfo Merged /alfresco/BRANCHES/DEV/BELARUS/ETHREEOH-2221:r14753 Merged /alfresco/BRANCHES/V2.1-A: lots Merged /alfresco/BRANCHES/V2.2:r14131,14332,14605,14607,14717,14745-14746,14759,14761,14885,14893,14903 Merged /alfresco/BRANCHES/V3.1:r14485,14915,14954,14966,14992,15080,15131,15134,15204,15214,15271,15352,15361,15369,15419,15431,15587,15616,15675,15818,15836,15840-15841,15860,15891 Merged /alfresco/BRANCHES/V3.2:r15897 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@16886 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -1861,6 +1861,33 @@ public abstract class BaseNodeServiceTest extends BaseSpringTest
|
||||
RegexQNamePattern.MATCH_ALL);
|
||||
}
|
||||
|
||||
public void testDuplicateChildAssocCleanup() throws Exception
|
||||
{
|
||||
Map<QName, ChildAssociationRef> assocRefs = buildNodeGraph();
|
||||
NodeRef n1Ref = assocRefs.get(QName.createQName(BaseNodeServiceTest.NAMESPACE,"root_p_n1")).getChildRef();
|
||||
ChildAssociationRef n1pn3Ref = assocRefs.get(QName.createQName(BaseNodeServiceTest.NAMESPACE,"n1_p_n3"));
|
||||
// Recreate the association from n1 to n3 i.e. duplicate it
|
||||
QName assocQName = QName.createQName(BaseNodeServiceTest.NAMESPACE, "dup");
|
||||
ChildAssociationRef dup1 = nodeService.addChild(
|
||||
n1pn3Ref.getParentRef(),
|
||||
n1pn3Ref.getChildRef(),
|
||||
n1pn3Ref.getTypeQName(),
|
||||
assocQName);
|
||||
ChildAssociationRef dup2 = nodeService.addChild(
|
||||
n1pn3Ref.getParentRef(),
|
||||
n1pn3Ref.getChildRef(),
|
||||
n1pn3Ref.getTypeQName(),
|
||||
assocQName);
|
||||
assertEquals("Duplicate not created", dup1, dup2);
|
||||
List<ChildAssociationRef> dupAssocs = nodeService.getChildAssocs(n1pn3Ref.getParentRef(), n1pn3Ref.getTypeQName(), assocQName);
|
||||
assertEquals("Expected duplicates", 2, dupAssocs.size());
|
||||
// Now delete the specific association
|
||||
nodeService.removeChildAssociation(dup1);
|
||||
|
||||
setComplete();
|
||||
endTransaction();
|
||||
}
|
||||
|
||||
public void testGetChildAssocsByChildType() throws Exception
|
||||
{
|
||||
/*
|
||||
|
@@ -110,6 +110,7 @@ import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||
import org.alfresco.service.cmr.repository.datatype.TypeConversionException;
|
||||
import org.alfresco.service.cmr.repository.datatype.TypeConverter;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.EqualsHelper;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.alfresco.util.Pair;
|
||||
@@ -193,6 +194,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
|
||||
private LocaleDAO localeDAO;
|
||||
private DictionaryService dictionaryService;
|
||||
private boolean enableTimestampPropagation;
|
||||
private TransactionService transactionService;
|
||||
private RetryingTransactionHelper auditableTransactionHelper;
|
||||
private BehaviourFilter behaviourFilter;
|
||||
/** A cache mapping StoreRef and NodeRef instances to the entity IDs (primary key) */
|
||||
@@ -306,6 +308,14 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
|
||||
this.enableTimestampPropagation = enableTimestampPropagation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes post-transaction code
|
||||
*/
|
||||
public void setTransactionService(TransactionService transactionService)
|
||||
{
|
||||
this.transactionService = transactionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the component to start new transactions when setting auditable properties (timestamps)
|
||||
* in the post-transaction phase.
|
||||
@@ -2746,6 +2756,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Pair<Long, ChildAssociationRef> getChildAssoc(
|
||||
final Long parentNodeId,
|
||||
final Long childNodeId,
|
||||
@@ -2774,20 +2785,97 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
|
||||
.setParameter("qnameNamespaceId", assocQNameNamespacePair.getFirst())
|
||||
.setParameter("qnameLocalName", assocQNameLocalName);
|
||||
DirtySessionMethodInterceptor.setQueryFlushMode(session, query);
|
||||
return query.uniqueResult();
|
||||
return query.list();
|
||||
}
|
||||
};
|
||||
ChildAssoc childAssoc = (ChildAssoc) getHibernateTemplate().execute(callback);
|
||||
if (childAssoc == null)
|
||||
@SuppressWarnings("unchecked")
|
||||
List<ChildAssoc> childAssocs = (List<ChildAssoc>) getHibernateTemplate().execute(callback);
|
||||
Pair<Long, ChildAssociationRef> ret = null;
|
||||
for (ChildAssoc childAssoc : childAssocs)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Pair<Long, ChildAssociationRef>(childAssoc.getId(), childAssoc.getChildAssocRef(qnameDAO));
|
||||
if (ret == null)
|
||||
{
|
||||
ret = new Pair<Long, ChildAssociationRef>(childAssoc.getId(), childAssoc.getChildAssocRef(qnameDAO));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Queue remaining assocs for a cleanup - they are duplicate
|
||||
new ChildAssocDeleteTransactionListener(childAssoc.getId());
|
||||
}
|
||||
}
|
||||
// Done
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Post-transaction removal of duplicate child associations.
|
||||
*
|
||||
* @author Derek Hulley
|
||||
* @since 2.2SP6
|
||||
*/
|
||||
private class ChildAssocDeleteTransactionListener extends TransactionListenerAdapter
|
||||
{
|
||||
private final Long childAssocId;
|
||||
|
||||
private ChildAssocDeleteTransactionListener(Long childAssocId)
|
||||
{
|
||||
this.childAssocId = childAssocId;
|
||||
AlfrescoTransactionSupport.bindListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (obj == this)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (obj == null || !(obj instanceof ChildAssocDeleteTransactionListener))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ChildAssocDeleteTransactionListener that = (ChildAssocDeleteTransactionListener) obj;
|
||||
return EqualsHelper.nullSafeEquals(this.childAssocId, that.childAssocId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return childAssocId == null ? 0 : childAssocId.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCommit()
|
||||
{
|
||||
if (transactionService.isReadOnly())
|
||||
{
|
||||
// Can't write to the repo
|
||||
return;
|
||||
}
|
||||
RetryingTransactionCallback<Void> deleteCallback = new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
deleteChildAssoc(childAssocId);
|
||||
if (logger.isInfoEnabled())
|
||||
{
|
||||
logger.debug("Cleaned up duplicate child assoc: " + childAssocId);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
try
|
||||
{
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(deleteCallback);
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
// This is the post-commit phase. Exceptions would be absorbed anyway.
|
||||
logger.warn("Failed to delete duplicate child association with ID " + childAssocId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Columns returned are:
|
||||
* <pre>
|
||||
|
Reference in New Issue
Block a user