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:
Derek Hulley
2009-10-13 20:08:41 +00:00
parent 34b82892b5
commit 2dd348a281
20 changed files with 669 additions and 130 deletions

View File

@@ -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
{
/*

View File

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