Merged V3.4-BUG-FIX

30520: Revisited timestamp propagation (cm:modified) now that the system does this by default
          - Original low-level code (Hibernate optimizations) pulled back into NodeService implementation
          - Use case driven prompting to touch the parent node
          - Full indexing and policy callbacks against parent (was missing completely)
          - Optimizations to ensure parent node modifications are only done where required and
            the same transaction is used where possible
          - 1s accuracy limit is maintained to prevent unnecessary modifications
          - Enhanced tests to cover use cases where propagation is expected
            - ALF-10262: Timestamp propagation is enabled by default
          - Fixes or will fix:
            - ALF-10291: Test disabled: SOLRTrackingComponentTest (various)
            - ALF-7433: A file deleted using the web UI still appears in a NFS mount but with NULL stats
            - ALF-10271: Test disabled: ArchiveAndRestoreTest.testAR7889ArchiveAndRestoreMustNotModifyAuditable
            - ALF-10267: Test disabled: NodeServiceTest.testArchiveAndRestore
         Also
          - Found problem where cm:auditable properties could be modified directly against the cached values
          - Extended locking of cached entities to the AuditablePropertiesEntity


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@30598 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2011-09-19 11:30:56 +00:00
parent 5e3cb4cb96
commit fb406b769b
14 changed files with 606 additions and 683 deletions

View File

@@ -100,6 +100,8 @@ public class AuditablePropertiesEntity
return typeDef.getDefaultAspectNames().contains(ContentModel.ASPECT_AUDITABLE);
}
private boolean locked;
private String auditCreator;
private String auditCreated;
private String auditModifier;
@@ -114,6 +116,21 @@ public class AuditablePropertiesEntity
*/
public AuditablePropertiesEntity()
{
locked = false;
}
/**
* Copy constructor to create an unlocked instance
*/
public AuditablePropertiesEntity(AuditablePropertiesEntity that)
{
locked = false;
this.auditCreator = that.auditCreator;
this.auditCreated = that.auditCreated;
this.auditModifier = that.auditModifier;
this.auditModified = that.auditModified;
this.auditAccessed = that.auditAccessed;
this.auditModifiedTime = that.auditModifiedTime;
}
@Override
@@ -129,6 +146,22 @@ public class AuditablePropertiesEntity
return sb.toString();
}
/**
* Lock the entity against further updates to prevent accidental modification
*/
public synchronized void lock()
{
locked = true;
}
private synchronized final void checkLock()
{
if (locked)
{
throw new IllegalStateException("The entity is locked against updates: " + this);
}
}
/**
* @param qname the property name
* @return Returns the value of the <b>cm:auditable</b> property or <tt>null</tt>
@@ -162,46 +195,6 @@ public class AuditablePropertiesEntity
}
}
/**
* @param qname the property name
* @param value the property value
* @return Returns <tt>true</tt> if the property was used
* @deprecated Deprecated from the start, but possibly useful code
*/
@SuppressWarnings("unused")
private boolean setAuditableProperty(QName qname, Serializable value)
{
if (qname.equals(ContentModel.PROP_CREATOR))
{
auditCreator = DefaultTypeConverter.INSTANCE.convert(String.class, value);
return true;
}
if (qname.equals(ContentModel.PROP_MODIFIER))
{
auditModifier = DefaultTypeConverter.INSTANCE.convert(String.class, value);
return true;
}
if (qname.equals(ContentModel.PROP_CREATED))
{
auditCreated = DefaultTypeConverter.INSTANCE.convert(String.class, value);
return true;
}
if (qname.equals(ContentModel.PROP_MODIFIED))
{
auditModified = DefaultTypeConverter.INSTANCE.convert(String.class, value);
return true;
}
if (qname.equals(ContentModel.PROP_ACCESSED))
{
auditAccessed = DefaultTypeConverter.INSTANCE.convert(String.class, value);
return true;
}
else
{
return false;
}
}
/**
* @return Returns a <tt>Map</tt> of auditable properties
*/
@@ -252,6 +245,8 @@ public class AuditablePropertiesEntity
*/
public boolean setAuditValues(String user, Date date, boolean force, long modifiedDateToleranceMs)
{
checkLock();
// Get a user if we need
if (user == null)
{
@@ -312,6 +307,8 @@ public class AuditablePropertiesEntity
*/
public boolean setAuditValues(String user, Date date, Map<QName, Serializable> properties)
{
checkLock();
// Need to know if anything changed
boolean changed = false;
@@ -431,6 +428,7 @@ public class AuditablePropertiesEntity
*/
public void setAuditCreator(String auditCreator)
{
checkLock();
this.auditCreator = auditCreator;
}
@@ -447,6 +445,7 @@ public class AuditablePropertiesEntity
*/
public void setAuditCreated(String auditCreated)
{
checkLock();
this.auditCreated = auditCreated;
}
@@ -463,6 +462,7 @@ public class AuditablePropertiesEntity
*/
public void setAuditModifier(String auditModifier)
{
checkLock();
this.auditModifier = auditModifier;
}
@@ -492,9 +492,34 @@ public class AuditablePropertiesEntity
*/
public void setAuditModified(String auditModified)
{
checkLock();
this.auditModified = auditModified;
}
/**
* @param modifiedDateToleranceMs the number of milliseconds' to tolerate before updating the
* modification date.
* Setting this to 1000L (say) will mean that the modification time will not be
* changed if the existing value is withing 1000 ms of the new time.
* @return Returns <tt>true</tt> if there were any changes made, otherwise <tt>false</tt>
*/
public boolean setAuditModified(Date date, long modifiedDateToleranceMs)
{
checkLock();
long dateTime = date.getTime();
long lastModTime = getAuditModifiedTime();
boolean changed = false;
if (lastModTime < 0 || (lastModTime + modifiedDateToleranceMs) < dateTime)
{
// The time has moved on enough
auditModifiedTime = dateTime;
auditModified = DefaultTypeConverter.INSTANCE.convert(String.class, date);
changed = true;
}
return changed;
}
/**
* For persistance use
*/
@@ -508,6 +533,7 @@ public class AuditablePropertiesEntity
*/
public void setAuditAccessed(String auditAccessed)
{
checkLock();
this.auditAccessed = auditAccessed;
}
}