#463 - ENH: Add @DraftReset support - property that is set to null on the draft been when it is published (@Draftable feature)

This commit is contained in:
Robin Bygrave
2015-11-25 11:06:14 +13:00
parent 5f194f066a
commit 4f51a3b130
7 changed files with 132 additions and 22 deletions
@@ -0,0 +1,19 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Marks a property on a @Draftable bean that is set to null on the 'draft bean' on publish.
* <p>
* This is expected to be put on properties that get 'reset' or 'cleared' after a publish.
* These properties might represent a publish comment or publish timestamp.
* </p>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface DraftReset {
}
@@ -837,6 +837,13 @@ public class BeanDescriptor<T> implements MetaBeanInfo, SpiBeanType<T> {
return draftHelp.publish(draftBean, liveBean);
}
/**
* Reset properties on the draft bean based on @DraftDirty and @DraftReset.
*/
public boolean draftReset(T draftBean) {
return draftHelp.draftReset(draftBean);
}
/**
* Return the draft dirty boolean property or null if there is not one assigned to this bean type.
*/
@@ -3,6 +3,9 @@ package com.avaje.ebeaninternal.server.deploy;
import com.avaje.ebean.Query;
import com.avaje.ebean.bean.EntityBean;
import java.util.ArrayList;
import java.util.List;
/**
* Helper for BeanDescriptor that manages draft entity beans.
*
@@ -12,16 +15,60 @@ public final class BeanDescriptorDraftHelp<T> {
private final BeanDescriptor<T> desc;
private final BeanProperty draftDirty;
private final BeanProperty[] resetProperties;
public BeanDescriptorDraftHelp(BeanDescriptor<T> desc) {
this.desc = desc;
this.draftDirty = desc.getDraftDirty();
this.resetProperties = resetProperties();
}
/**
*
* Return the properties that are reset on draft beans after publish.
*/
public void initialise() {
private BeanProperty[] resetProperties() {
List<BeanProperty> list = new ArrayList<BeanProperty>();
BeanProperty[] props = desc.propertiesNonMany();
for (BeanProperty prop : props) {
if (prop.isDraftReset()) {
list.add(prop);
}
}
return list.toArray(new BeanProperty[list.size()]);
}
/**
* Set the value of all the 'reset properties' to null on the draft bean.
*/
public boolean draftReset(T draftBean) {
EntityBean draftEntityBean = (EntityBean)draftBean;
if (draftDirty != null) {
// set @DraftDirty property to false
draftDirty.setValueIntercept(draftEntityBean, false);
}
// set to null on all @DraftReset properties
for (BeanProperty resetProperty : resetProperties) {
resetProperty.setValueIntercept(draftEntityBean, null);
}
// return true if the bean is dirty (and should be persisted)
return draftEntityBean._ebean_getIntercept().isDirty();
}
/**
* Transfer the values from the draftBean to the liveBean.
* <p>
* This will recursive transfer values to all @DraftableElement properties.
* </p>
*/
public T publish(T draftBean, T liveBean) {
if (liveBean == null) {
@@ -227,6 +227,8 @@ public class BeanProperty implements ElPropertyValue {
final boolean draftDirty;
final boolean draftReset;
final boolean indexed;
final String indexName;
@@ -255,6 +257,7 @@ public class BeanProperty implements ElPropertyValue {
this.excludedFromHistory = deploy.isExcludedFromHistory();
this.draftDirty = deploy.isDraftDirty();
this.draftOnly = deploy.isDraftOnly();
this.draftReset = deploy.isDraftReset();
this.secondaryTable = deploy.isSecondaryTable();
if (secondaryTable) {
@@ -341,6 +344,7 @@ public class BeanProperty implements ElPropertyValue {
this.excludedFromHistory = source.excludedFromHistory;
this.draftDirty = source.draftDirty;
this.draftOnly = source.draftOnly;
this.draftReset = source.draftReset;
this.fetchEager = source.fetchEager;
this.unidirectionalShadow = source.unidirectionalShadow;
this.discriminator = source.discriminator;
@@ -1045,6 +1049,13 @@ public class BeanProperty implements ElPropertyValue {
return draftDirty;
}
/**
* Return true if this property is reset/cleared on publish (on the draft bean).
*/
public boolean isDraftReset() {
return draftReset;
}
/**
* Return true if this property should be included in an Insert.
*/
@@ -185,6 +185,7 @@ public class DeployBeanProperty {
private boolean draftOnly;
private boolean draftDirty;
private boolean draftReset;
public DeployBeanProperty(DeployBeanDescriptor<?> desc, Class<?> propertyType, ScalarType<?> scalarType, ScalarTypeConverter<?, ?> typeConverter) {
this.desc = desc;
@@ -854,4 +855,12 @@ public class DeployBeanProperty {
public boolean isDraftDirty() {
return draftDirty;
}
public void setDraftReset() {
this.draftReset = true;
}
public boolean isDraftReset() {
return draftReset;
}
}
@@ -152,10 +152,12 @@ public class AnnotationFields extends AnnotationParser {
if (get(prop, DraftOnly.class) != null) {
prop.setDraftOnly();
}
if (get(prop, DraftDirty.class) != null) {
prop.setDraftDirty();
}
if (get(prop, DraftReset.class) != null) {
prop.setDraftReset();
}
DbJson dbJson = get(prop, DbJson.class);
if (dbJson != null) {
@@ -159,10 +159,7 @@ public final class DefaultPersister implements Persister {
BeanManager<T> mgr = beanDescriptorManager.getBeanManager(beanType);
// collect a list of draft beans that have had their
// dirty status set back to false by the publish
List<T> draftUpdates = new ArrayList<T>();
BeanProperty draftDirty = desc.getDraftDirty();
DraftHandler draftHandler = new DraftHandler(desc);
for (T draftBean: draftBeans) {
Object draftID = desc.getBeanId(draftBean);
@@ -181,34 +178,52 @@ public final class DefaultPersister implements Persister {
update(request);
}
unsetDraftDirtyProperty(draftUpdates, draftDirty, draftBean);
draftHandler.resetDraft(draftBean);
}
if (!draftUpdates.isEmpty()) {
// update the dirty status on the drafts that have been published
PUB.debug("publish - update dirty status on [{}] drafts", draftUpdates.size());
for (T draftUpdate : draftUpdates) {
update(createRequest(draftUpdate, transaction, null, mgr, Type.UPDATE, false, false));
}
}
draftHandler.updateDrafts(transaction, mgr);
PUB.debug("publish - complete for [{}]", desc.getName());
return livePublish;
}
/**
* Set the draft dirty state to false and add to the draftUpdates list.
* Helper to handle draft beans (properties reset etc).
*/
private <T> void unsetDraftDirtyProperty(List<T> draftUpdates, BeanProperty draftDirty, T draftBean) {
class DraftHandler<T> {
if (draftDirty != null) {
EntityBean draftEntityBean = (EntityBean)draftBean;
draftDirty.setValueIntercept(draftEntityBean, false);
if (draftEntityBean._ebean_getIntercept().isDirty()) {
final BeanDescriptor<T> desc;
final BeanProperty draftDirty;
final List<T> draftUpdates = new ArrayList<T>();
DraftHandler(BeanDescriptor<T> desc) {
this.desc = desc;
this.draftDirty = desc.getDraftDirty();
}
/**
* Set the draft dirty state to false and reset any dirtyReset properties.
*/
void resetDraft(T draftBean) {
if (desc.draftReset(draftBean)) {
// draft bean is dirty so collect it for persisting later
draftUpdates.add(draftBean);
}
}
/**
* Save all the draft beans (with various properties reset etc).
*/
void updateDrafts(Transaction transaction, BeanManager<T> mgr) {
if (!draftUpdates.isEmpty()) {
// update the dirty status on the drafts that have been published
PUB.debug("publish - update dirty status on [{}] drafts", draftUpdates.size());
for (T draftUpdate : draftUpdates) {
update(createRequest(draftUpdate, transaction, null, mgr, Type.UPDATE, false, false));
}
}
}
}
/**