Created
November 12, 2012 11:23
-
-
Save marcpalmer/4058815 to your computer and use it in GitHub Desktop.
Dynamic methods for retrospectively locking domain objects and merging changes in
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private copyDirtyProperties(src, target) { | |
for (name in src.dirtyPropertyNames) { | |
target[name] = src[name] | |
} | |
} | |
private copyDirtyPropertiesNotChangedInTarget(src, target) { | |
for (name in src.dirtyPropertyNames) { | |
if (target[name] == src.getPersistentValue(name)) { | |
target[name] = src[name] | |
} | |
} | |
} | |
private copyPersistentProperties(src, target) { | |
def artefact = grailsApplication.getArtefact(DomainClassArtefactHandler.TYPE, src.getClass().name) | |
for (prop in artefact.persistentProperties) { | |
target[prop.name] = src[prop.name] | |
} | |
} | |
// Now somewhere i.e. in BootStrap... | |
grailsApplication.domainClasses.clazz.each { domainClass -> | |
def domainMetaClass = domainClass.metaClass | |
domainMetaClass.lockUpdateAndRefresh = { Closure updateCode -> | |
def lockedSelf = delegate.getClass().lock(delegate.ident()) | |
updateCode(lockedSelf) | |
delegate.refresh() | |
} | |
// Obtain lock. If stale, re-load locked and | |
// merge our existing *dirty* properties according to | |
// merge policies: | |
// Changes we've made will overwrite anything new from the DB | |
domainMetaClass.lockAndMergeSessionIn = { -> | |
def lockedSelf = delegate.getClass().lock(delegate.ident()) | |
copyDirtyProperties(delegate, lockedSelf) | |
delegate.refresh() | |
} | |
// Changes to the DB will survive, anything we also changed | |
// will be lost | |
domainMetaClass.lockAndMergeDatabaseIn = { -> | |
def lockedSelf = delegate.getClass().lock(delegate.ident()) | |
copyDirtyPropertiesNotChangedInTarget(delegate, lockedSelf) | |
delegate.refresh() | |
} | |
// Exactly the values we have for all properties will be used | |
// all values from the DB will be lost even if changed and | |
// they weren't change in this session (coherent) | |
domainMetaClass.lockAndOverwrite = { -> | |
def lockedSelf = delegate.getClass().lock(delegate.ident()) | |
copyPersistentProperties(delegate, lockedSelf) | |
delegate.refresh() | |
} | |
// Attempt a lock but if DB changed since object was loaded, | |
// catch the exception and execute the Closure | |
domainMetaClass.lockAndIfStale = { Closure staleHandler -> | |
try { | |
delegate.lock() | |
} catch (Exception e) { // Need specific types here, there's a couple | |
staleHandler(delegate) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment