From c95d76d6f6a9241e93ad892bc4ba2da9d2d121f9 Mon Sep 17 00:00:00 2001 From: rbygrave Date: Wed, 19 Nov 2014 19:43:34 +1300 Subject: [PATCH] Fix for #201: Change BeanPersistListener to use isRegisterFor() method rather than generics type (just like BeanPersistController) --- .../com/avaje/ebean/config/ServerConfig.java | 8 +- .../event/AbstractBeanPersistListener.java | 78 ++++++ .../ebean/event/BeanPersistListener.java | 16 +- .../server/core/BootupClasses.java | 10 +- .../server/core/PersistRequestBean.java | 14 +- .../server/deploy/BeanDescriptor.java | 222 ++---------------- .../deploy/ChainedBeanPersistListener.java | 43 ++-- .../server/deploy/PersistListenerManager.java | 32 +-- .../deploy/meta/DeployBeanDescriptor.java | 36 +-- .../server/transaction/BeanPersistIds.java | 2 +- .../avaje/tests/basic/TestExplicitInsert.java | 26 +- .../model/basic/MyEBasicConfigStartup.java | 47 ++-- 12 files changed, 215 insertions(+), 319 deletions(-) create mode 100644 src/main/java/com/avaje/ebean/event/AbstractBeanPersistListener.java diff --git a/src/main/java/com/avaje/ebean/config/ServerConfig.java b/src/main/java/com/avaje/ebean/config/ServerConfig.java index 88a45be1e..2330f7e59 100644 --- a/src/main/java/com/avaje/ebean/config/ServerConfig.java +++ b/src/main/java/com/avaje/ebean/config/ServerConfig.java @@ -225,7 +225,7 @@ public class ServerConfig { private List persistControllers = new ArrayList(); - private List> persistListeners = new ArrayList>(); + private List persistListeners = new ArrayList(); private List queryAdapters = new ArrayList(); private List bulkTableEventListeners = new ArrayList(); private List configStartupListeners = new ArrayList(); @@ -1255,14 +1255,14 @@ public class ServerConfig { * all the BeanPersistListener instances. *

*/ - public void add(BeanPersistListener beanPersistListener) { + public void add(BeanPersistListener beanPersistListener) { persistListeners.add(beanPersistListener); } /** * Return the BeanPersistListener instances. */ - public List> getPersistListeners() { + public List getPersistListeners() { return persistListeners; } @@ -1301,7 +1301,7 @@ public class ServerConfig { * BeanPersistListener instances one at a time. *

*/ - public void setPersistListeners(List> persistListeners) { + public void setPersistListeners(List persistListeners) { this.persistListeners = persistListeners; } diff --git a/src/main/java/com/avaje/ebean/event/AbstractBeanPersistListener.java b/src/main/java/com/avaje/ebean/event/AbstractBeanPersistListener.java new file mode 100644 index 000000000..000d39b1f --- /dev/null +++ b/src/main/java/com/avaje/ebean/event/AbstractBeanPersistListener.java @@ -0,0 +1,78 @@ +package com.avaje.ebean.event; + +import java.util.Set; + +/** + * Provides a base implementation of BeanPersistListener. + *

+ * Objects extending this should override the methods then are interested in. + * The default inserted() updated() and deleted() methods return false and as such + * means other servers in the cluster are not notified. + *

+ */ +public abstract class AbstractBeanPersistListener implements BeanPersistListener { + + /** + * Notified that a bean has been inserted locally. Return true if you want the + * cluster to be notified of the event. + * + * @param bean The bean that was inserted. + */ + @Override + public boolean inserted(Object bean) { + return false; + } + + /** + * Notified that a bean has been updated locally. Return true if you want the + * cluster to be notified of the event. + * + * @param bean The bean that was updated. + * @param updatedProperties The properties that were modified by this update. + */ + @Override + public boolean updated(Object bean, Set updatedProperties) { + return false; + } + + /** + * Notified that a bean has been deleted locally. Return true if you want the + * cluster to be notified of the event. + * + * @param bean The bean that was deleted. + */ + @Override + public boolean deleted(Object bean) { + return false; + } + + /** + * Notify that a bean was inserted on another node of the cluster. + * + * @param id the id value of the inserted bean + */ + @Override + public void remoteInsert(Object id) { + // do nothing + } + + /** + * Notify that a bean was updated on another node of the cluster. + * + * @param id the id value of the updated bean. + */ + @Override + public void remoteUpdate(Object id) { + // do nothing + } + + /** + * Notify that a bean was deleted on another node of the cluster. + * + * @param id the id value of the deleted bean. + */ + @Override + public void remoteDelete(Object id) { + // do nothing + } +} diff --git a/src/main/java/com/avaje/ebean/event/BeanPersistListener.java b/src/main/java/com/avaje/ebean/event/BeanPersistListener.java index 1f9d6e32a..9b453f6dd 100644 --- a/src/main/java/com/avaje/ebean/event/BeanPersistListener.java +++ b/src/main/java/com/avaje/ebean/event/BeanPersistListener.java @@ -33,11 +33,17 @@ import com.avaje.ebean.config.ServerConfig; *

*

* A BeanPersistListener is either found automatically via class path search or - * can be added programmatically via {@link ServerConfig#add(BeanPersistListener)}. + * can be added programmatically via {@link ServerConfig#add(BeanPersistListener)}}. *

* @see ServerConfig#add(BeanPersistListener) */ -public interface BeanPersistListener { +public interface BeanPersistListener { + + /** + * Return true if this BeanPersistListener should be registered for events + * on this entity type. + */ + public boolean isRegisterFor(Class cls); /** * Notified that a bean has been inserted locally. Return true if you want the @@ -46,7 +52,7 @@ public interface BeanPersistListener { * @param bean * The bean that was inserted. */ - public boolean inserted(T bean); + public boolean inserted(Object bean); /** * Notified that a bean has been updated locally. Return true if you want the @@ -57,7 +63,7 @@ public interface BeanPersistListener { * @param updatedProperties * The properties that were modified by this update. */ - public boolean updated(T bean, Set updatedProperties); + public boolean updated(Object bean, Set updatedProperties); /** * Notified that a bean has been deleted locally. Return true if you want the @@ -66,7 +72,7 @@ public interface BeanPersistListener { * @param bean * The bean that was deleted. */ - public boolean deleted(T bean); + public boolean deleted(Object bean); /** * Notify that a bean was inserted on another node of the cluster. diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/BootupClasses.java b/src/main/java/com/avaje/ebeaninternal/server/core/BootupClasses.java index 765c16b3a..2a28160aa 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/BootupClasses.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/BootupClasses.java @@ -56,7 +56,7 @@ public class BootupClasses implements ClassPathSearchMatcher { private ArrayList serverConfigStartupInstances = new ArrayList(); private List persistControllerInstances = new ArrayList(); - private List> persistListenerInstances = new ArrayList>(); + private List persistListenerInstances = new ArrayList(); private List queryAdapterInstances = new ArrayList(); private List transactionEventListenerInstances = new ArrayList(); @@ -145,9 +145,9 @@ public class BootupClasses implements ClassPathSearchMatcher { } } - public void addPersistListeners(List> listenerInstances) { + public void addPersistListeners(List listenerInstances) { if (listenerInstances != null) { - for (BeanPersistListener l : listenerInstances) { + for (BeanPersistListener l : listenerInstances) { this.persistListenerInstances.add(l); // don't automatically instantiate this.beanListenerList.remove(l.getClass()); @@ -181,12 +181,12 @@ public class BootupClasses implements ClassPathSearchMatcher { return queryAdapterInstances; } - public List> getBeanPersistListeners() { + public List getBeanPersistListeners() { // add class registered BeanPersistController to the // already created instances for (Class cls : beanListenerList) { try { - BeanPersistListener newInstance = (BeanPersistListener) cls.newInstance(); + BeanPersistListener newInstance = (BeanPersistListener) cls.newInstance(); persistListenerInstances.add(newInstance); } catch (Exception e) { String msg = "Error creating BeanPersistController " + cls; diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java b/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java index 210cc03c3..3e80e1837 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java @@ -38,7 +38,7 @@ public final class PersistRequestBean extends PersistRequest implements BeanP private final BeanDescriptor beanDescriptor; - private final BeanPersistListener beanPersistListener; + private final BeanPersistListener beanPersistListener; /** * For per post insert update delete control. @@ -91,6 +91,12 @@ public final class PersistRequestBean extends PersistRequest implements BeanP */ private List> updatedManys; + /** + * Need to get and store the updated properties because the persist listener is notified + * later on a different thread and the bean has been reset at that point. + */ + private Set updatedProperties; + public PersistRequestBean(SpiEbeanServer server, T bean, Object parentBean, BeanManager mgr, SpiTransaction t, PersistExecute persistExecute, PersistRequest.Type type, boolean saveRecurse) { @@ -188,7 +194,7 @@ public final class PersistRequestBean extends PersistRequest implements BeanP return beanPersistListener.inserted(bean); case UPDATE: - return beanPersistListener.updated(bean, intercept.getDirtyPropertyNames()); + return beanPersistListener.updated(bean, updatedProperties); case DELETE: return beanPersistListener.deleted(bean); @@ -372,6 +378,10 @@ public final class PersistRequestBean extends PersistRequest implements BeanP return -1; case UPDATE: + if (beanPersistListener != null) { + // store the updated properties for sending later + updatedProperties = getUpdatedProperties(); + } persistExecute.executeUpdateBean(this); return -1; diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java index 15f11c47d..5e564cb56 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java @@ -134,11 +134,6 @@ public class BeanDescriptor implements MetaBeanInfo { private final CompoundUniqueContraint[] compoundUniqueConstraints; - /** - * Extra deployment attributes. - */ - private final Map extraAttrMap; - /** * The base database table. */ @@ -175,7 +170,7 @@ public class BeanDescriptor implements MetaBeanInfo { /** * Listens for post commit insert update and delete events. */ - private volatile BeanPersistListener persistListener; + private volatile BeanPersistListener persistListener; private volatile BeanQueryAdapter queryAdapter; @@ -225,17 +220,6 @@ public class BeanDescriptor implements MetaBeanInfo { private final BeanPropertyAssocOne unidirectional; - /** - * A hashcode of all the many property names. This is used to efficiently - * create sets of loaded property names (for partial objects). - */ - private final int namesOfManyPropsHash; - - /** - * The set of names of the many properties. - */ - private final Set namesOfManyProps; - /** * list of properties that are Lists/Sets/Maps (Derived). */ @@ -376,8 +360,6 @@ public class BeanDescriptor implements MetaBeanInfo { this.dependantTables = deploy.getDependantTables(); this.compoundUniqueConstraints = deploy.getCompoundUniqueConstraints(); - this.extraAttrMap = deploy.getExtraAttributeMap(); - this.baseTable = InternString.intern(deploy.getBaseTable()); this.autoFetchTunable = EntityType.ORM.equals(entityType) && (beanFinder == null); @@ -411,9 +393,6 @@ public class BeanDescriptor implements MetaBeanInfo { this.propertiesManyDelete = listHelper.getManyDelete(); this.propertiesManyToMany = listHelper.getManyToMany(); - this.namesOfManyProps = deriveManyPropNames(); - this.namesOfManyPropsHash = namesOfManyProps.hashCode(); - this.derivedTableJoins = listHelper.getTableJoin(); boolean noRelationships = propertiesOne.length + propertiesMany.length == 0; @@ -518,48 +497,6 @@ public class BeanDescriptor implements MetaBeanInfo { } } - /** - * Determine the concurrency mode based on the existence of a non-null version - * property value. - */ - public ConcurrencyMode determineConcurrencyMode(EntityBean bean) { - - if (versionProperty == null) { - return ConcurrencyMode.NONE; - } - Object v = versionProperty.getValue(bean); - return (v == null) ? ConcurrencyMode.NONE : ConcurrencyMode.VERSION; - } - - /** - * Return the Set of embedded beans that have changed. - */ - public Set getDirtyEmbeddedProperties(EntityBean bean) { - - HashSet dirtyProperties = null; - - for (int i = 0; i < propertiesEmbedded.length; i++) { - Object embValue = propertiesEmbedded[i].getValue(bean); - if (embValue instanceof EntityBean) { - if (((EntityBean) embValue)._ebean_getIntercept().isDirty()) { - // this embedded is dirty so should be included in an update - if (dirtyProperties == null) { - dirtyProperties = new HashSet(); - } - dirtyProperties.add(propertiesEmbedded[i].getName()); - } - } else { - // must assume it is dirty - if (dirtyProperties == null) { - dirtyProperties = new HashSet(); - } - dirtyProperties.add(propertiesEmbedded[i].getName()); - } - } - - return dirtyProperties; - } - /** * Return the EbeanServer instance that owns this BeanDescriptor. */ @@ -667,10 +604,6 @@ public class BeanDescriptor implements MetaBeanInfo { cacheHelp.initialise(); } - protected boolean hasInheritance() { - return inheritInfo != null; - } - public SqlUpdate deleteById(Object id, List idList) { if (id != null) { return deleteById(id); @@ -838,8 +771,6 @@ public class BeanDescriptor implements MetaBeanInfo { cacheHelp.queryCachePut(id, query); } - - /** * Try to load the beanCollection from cache return true if successful. */ @@ -1030,11 +961,10 @@ public class BeanDescriptor implements MetaBeanInfo { /** * Execute the postLoad if a BeanPersistController exists for this bean. */ - @SuppressWarnings("unchecked") public void postLoad(Object bean, Set includedProperties) { BeanPersistController c = persistController; if (c != null) { - c.postLoad((T) bean, includedProperties); + c.postLoad(bean, includedProperties); } } @@ -1060,13 +990,6 @@ public class BeanDescriptor implements MetaBeanInfo { updatePlanCache.put(key, plan); } - /** - * Return the TypeManager. - */ - public TypeManager getTypeManager() { - return typeManager; - } - /** * Return true if updates should only include changed properties. Otherwise * all loaded properties are included in the update. @@ -1194,7 +1117,7 @@ public class BeanDescriptor implements MetaBeanInfo { public T createReference(Boolean readOnly, Object id) { if (cacheSharableBeans && !Boolean.FALSE.equals(readOnly)) { - CachedBeanData d = (CachedBeanData) cacheHelp.beanCacheGetData(id); + CachedBeanData d = cacheHelp.beanCacheGetData(id); if (d != null) { Object shareableBean = d.getSharableBean(); if (shareableBean != null) { @@ -1220,13 +1143,6 @@ public class BeanDescriptor implements MetaBeanInfo { } } - /** - * Return the BeanProperty for the given deployment name. - */ - public BeanProperty getBeanPropertyFromDbColumn(String dbColumn) { - return propMapByDbColumn.get(dbColumn); - } - /** * Return the bean property traversing the object graph and taking into * account inheritance. @@ -1355,14 +1271,6 @@ public class BeanDescriptor implements MetaBeanInfo { return (idProperty == null) ? null : idProperty.getValue(bean); } - /** - * Return false if the id is a simple scalar and false if it is embedded or - * concatenated. - */ - public boolean isComplexId() { - return idBinder.isComplexId(); - } - /** * Return the default order by that may need to be added if a many property is * included in the query. @@ -1393,7 +1301,7 @@ public class BeanDescriptor implements MetaBeanInfo { * Get a BeanProperty by its name. */ public BeanProperty getBeanProperty(String propName) { - return (BeanProperty) propMap.get(propName); + return propMap.get(propName); } public void sort(List list, String sortByClause) { @@ -1572,13 +1480,6 @@ public class BeanDescriptor implements MetaBeanInfo { return prop; } - protected Object getBeanPropertyWithInheritance(EntityBean bean, String propName) { - - BeanDescriptor desc = getBeanDescriptor(bean.getClass()); - BeanProperty beanProperty = desc.findBeanProperty(propName); - return beanProperty.getValue(bean); - } - /** * Return the name of the server this BeanDescriptor belongs to. */ @@ -1619,17 +1520,6 @@ public class BeanDescriptor implements MetaBeanInfo { return EntityType.EMBEDDED.equals(entityType); } - public boolean isBaseTableType() { - return EntityType.ORM.equals(entityType); - } - - /** - * Return the concurrency mode used for beans of this type. - */ - public ConcurrencyMode getConcurrencyMode() { - return concurrencyMode; - } - /** * Return the tables this bean is dependent on. This implies that if any of * these tables are modified then cached beans may be invalidated. @@ -1648,7 +1538,7 @@ public class BeanDescriptor implements MetaBeanInfo { /** * Return the beanListener. */ - public BeanPersistListener getPersistListener() { + public BeanPersistListener getPersistListener() { return persistListener; } @@ -1670,16 +1560,16 @@ public class BeanDescriptor implements MetaBeanInfo { * De-register the BeanPersistListener. */ @SuppressWarnings("unchecked") - public void deregister(BeanPersistListener listener) { + public void deregister(BeanPersistListener listener) { // volatile read... - BeanPersistListener currListener = persistListener; + BeanPersistListener currListener = persistListener; if (currListener == null) { // nothing to deregister } else { - BeanPersistListener deregListener = (BeanPersistListener) listener; - if (currListener instanceof ChainedBeanPersistListener) { + BeanPersistListener deregListener = listener; + if (currListener instanceof ChainedBeanPersistListener) { // remove it from the existing chain - persistListener = ((ChainedBeanPersistListener) currListener).deregister(deregListener); + persistListener = ((ChainedBeanPersistListener) currListener).deregister(deregListener); } else if (currListener.equals(deregListener)) { persistListener = null; } @@ -1692,9 +1582,7 @@ public class BeanDescriptor implements MetaBeanInfo { public void deregister(BeanPersistController controller) { // volatile read... BeanPersistController c = persistController; - if (c == null) { - // nothing to deregister - } else { + if (c != null) { if (c instanceof ChainedBeanPersistController) { // remove it from the existing chain persistController = ((ChainedBeanPersistController) c).deregister(controller); @@ -1708,23 +1596,20 @@ public class BeanDescriptor implements MetaBeanInfo { * Register the new BeanPersistController. */ @SuppressWarnings("unchecked") - public void register(BeanPersistListener newPersistListener) { + public void register(BeanPersistListener newPersistListener) { - if (!PersistListenerManager.isRegisterFor(beanType, newPersistListener)) { - // skip - } else { - BeanPersistListener newListener = (BeanPersistListener) newPersistListener; + if (newPersistListener.isRegisterFor(beanType)) { // volatile read... - BeanPersistListener currListener = persistListener; + BeanPersistListener currListener = persistListener; if (currListener == null) { - persistListener = newListener; + persistListener = newPersistListener; } else { - if (currListener instanceof ChainedBeanPersistListener) { + if (currListener instanceof ChainedBeanPersistListener) { // add it to the existing chain - persistListener = ((ChainedBeanPersistListener) currListener).register(newListener); + persistListener = ((ChainedBeanPersistListener) currListener).register(newPersistListener); } else { // build new chain of the 2 - persistListener = new ChainedBeanPersistListener(currListener, newListener); + persistListener = new ChainedBeanPersistListener(currListener, newPersistListener); } } } @@ -1735,9 +1620,7 @@ public class BeanDescriptor implements MetaBeanInfo { */ public void register(BeanPersistController newController) { - if (!newController.isRegisterFor(beanType)) { - // skip - } else { + if (newController.isRegisterFor(beanType)) { // volatile read... BeanPersistController c = persistController; if (c == null) { @@ -1781,13 +1664,6 @@ public class BeanDescriptor implements MetaBeanInfo { return baseTable; } - /** - * Get a named extra attribute. - */ - public String getExtraAttribute(String key) { - return (String) extraAttrMap.get(key); - } - /** * Return the identity generation type. */ @@ -1906,17 +1782,11 @@ public class BeanDescriptor implements MetaBeanInfo { } public boolean hasIdProperty(EntityBeanIntercept ebi) { - if (idPropertyIndex > -1) { - return ebi.isLoadedProperty(idPropertyIndex); - } - return false; + return idPropertyIndex > -1 && ebi.isLoadedProperty(idPropertyIndex); } public boolean hasVersionProperty(EntityBeanIntercept ebi) { - if (versionPropertyIndex > -1) { - return ebi.isLoadedProperty(versionPropertyIndex); - } - return false; + return versionPropertyIndex > -1 && ebi.isLoadedProperty(versionPropertyIndex); } /** @@ -1979,16 +1849,6 @@ public class BeanDescriptor implements MetaBeanInfo { return propertiesOneImportedDelete; } - /** - * Returns OneToOnes that are on the exported side of a OneToOne. - *

- * These associations do not own the relationship. - *

- */ - public BeanPropertyAssocOne[] propertiesOneExported() { - return propertiesOneExported; - } - /** * Exported assoc ones with cascade save. */ @@ -2003,32 +1863,6 @@ public class BeanDescriptor implements MetaBeanInfo { return propertiesOneExportedDelete; } - private Set deriveManyPropNames() { - - LinkedHashSet names = new LinkedHashSet(); - for (int i = 0; i < propertiesMany.length; i++) { - names.add(propertiesMany[i].getName()); - } - - return Collections.unmodifiableSet(names); - } - - /** - * Return a hash of the names of the many properties on this bean type. This - * is used for efficient building of included properties sets for partial - * objects. - */ - public int getNamesOfManyPropsHash() { - return namesOfManyPropsHash; - } - - /** - * Returns the set of many property names for this bean type. - */ - public Set getNamesOfManyProps() { - return namesOfManyProps; - } - /** * All Non Assoc Many's for this descriptor. */ @@ -2075,20 +1909,6 @@ public class BeanDescriptor implements MetaBeanInfo { return versionProperty; } - /** - * Return true if this is an Update (rather than insert) given that the bean - * is involved in a stateless update. - */ - public boolean isStatelessUpdate(EntityBean bean) { - if (versionProperty == null) { - Object versionValue = getId(bean); - return !DmlUtil.isNullOrZero(versionValue); - } else { - Object versionValue = versionProperty.getValue(bean); - return !DmlUtil.isNullOrZero(versionValue); - } - } - /** * Scalar properties without the unique id or secondary table properties. */ diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/ChainedBeanPersistListener.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/ChainedBeanPersistListener.java index a0dc8a7fc..889dbd164 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/ChainedBeanPersistListener.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/ChainedBeanPersistListener.java @@ -9,24 +9,30 @@ import com.avaje.ebean.event.BeanPersistListener; /** * Handles multiple BeanPersistListener's for a given entity type. */ -public class ChainedBeanPersistListener implements BeanPersistListener { +public class ChainedBeanPersistListener implements BeanPersistListener { - private final List> list; + private final List list; - private final BeanPersistListener[] chain; + private final BeanPersistListener[] chain; /** * Construct adding 2 BeanPersistController's. */ - public ChainedBeanPersistListener(BeanPersistListener c1, BeanPersistListener c2) { + public ChainedBeanPersistListener(BeanPersistListener c1, BeanPersistListener c2) { this(addList(c1, c2)); } - - /** + + @Override + public boolean isRegisterFor(Class cls) { + // never called + return false; + } + + /** * Helper method used to create a list from 2 BeanPersistListener. */ - private static List> addList(BeanPersistListener c1, BeanPersistListener c2) { - ArrayList> addList = new ArrayList>(2); + private static List addList(BeanPersistListener c1, BeanPersistListener c2) { + ArrayList addList = new ArrayList(2); addList.add(c1); addList.add(c2); return addList; @@ -36,8 +42,7 @@ public class ChainedBeanPersistListener implements BeanPersistListener { * Construct given the list of BeanPersistController's. * @param list */ - @SuppressWarnings("unchecked") - public ChainedBeanPersistListener(List> list) { + public ChainedBeanPersistListener(List list) { this.list = list; this.chain = list.toArray(new BeanPersistListener[list.size()]); } @@ -45,35 +50,35 @@ public class ChainedBeanPersistListener implements BeanPersistListener { /** * Register a new BeanPersistController and return the resulting chain. */ - public ChainedBeanPersistListener register(BeanPersistListener c) { + public ChainedBeanPersistListener register(BeanPersistListener c) { if (list.contains(c)){ return this; } else { - List> newList = new ArrayList>(); + List newList = new ArrayList(); newList.addAll(list); newList.add(c); - return new ChainedBeanPersistListener(newList); + return new ChainedBeanPersistListener(newList); } } /** * De-register a BeanPersistController and return the resulting chain. */ - public ChainedBeanPersistListener deregister(BeanPersistListener c) { + public ChainedBeanPersistListener deregister(BeanPersistListener c) { if (!list.contains(c)){ return this; } else { - ArrayList> newList = new ArrayList>(); + ArrayList newList = new ArrayList(); newList.addAll(list); newList.remove(c); - return new ChainedBeanPersistListener(newList); + return new ChainedBeanPersistListener(newList); } } - public boolean deleted(T bean) { + public boolean deleted(Object bean) { boolean notifyCluster = false; for (int i = 0; i < chain.length; i++) { if (chain[i].deleted(bean)) { @@ -83,7 +88,7 @@ public class ChainedBeanPersistListener implements BeanPersistListener { return notifyCluster; } - public boolean inserted(T bean) { + public boolean inserted(Object bean) { boolean notifyCluster = false; for (int i = 0; i < chain.length; i++) { if (chain[i].inserted(bean)) { @@ -111,7 +116,7 @@ public class ChainedBeanPersistListener implements BeanPersistListener { } } - public boolean updated(T bean, Set updatedProperties) { + public boolean updated(Object bean, Set updatedProperties) { boolean notifyCluster = false; for (int i = 0; i < chain.length; i++) { if (chain[i].updated(bean, updatedProperties)) { diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/PersistListenerManager.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/PersistListenerManager.java index 90fe3e472..97c794116 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/PersistListenerManager.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/PersistListenerManager.java @@ -18,7 +18,7 @@ public class PersistListenerManager { private static final Logger logger = LoggerFactory.getLogger(PersistListenerManager.class); - private final List> list; + private final List list; public PersistListenerManager(BootupClasses bootupClasses) { list = bootupClasses.getBeanPersistListeners(); @@ -31,37 +31,15 @@ public class PersistListenerManager { /** * Return the BeanPersistController for a given entity type. */ - @SuppressWarnings("unchecked") public void addPersistListeners(DeployBeanDescriptor deployDesc) { for (int i = 0; i < list.size(); i++) { - BeanPersistListener c = list.get(i); - if (isRegisterFor(deployDesc.getBeanType(), c)) { - logger.debug("BeanPersistListener on[" + deployDesc.getFullName() + "] " + c.getClass().getName()); - deployDesc.addPersistListener((BeanPersistListener) c); + BeanPersistListener listener = list.get(i); + if (listener.isRegisterFor(deployDesc.getBeanType())) { + logger.debug("BeanPersistListener on[{}] {}", deployDesc.getFullName(), listener.getClass().getName()); + deployDesc.addPersistListener(listener); } } } - public static boolean isRegisterFor(Class beanType, BeanPersistListener c) { - Class listenerEntity = getEntityClass(c.getClass()); - return beanType.equals(listenerEntity); - } - - /** - * Find the entity class given the controller class. - *

- * This uses reflection to find the generics parameter type. - *

- */ - private static Class getEntityClass(Class controller) { - - Class cls = ParamTypeUtil.findParamType(controller, BeanPersistListener.class); - if (cls == null) { - String msg = "Could not determine the entity class (generics parameter type) from " + controller - + " using reflection."; - throw new PersistenceException(msg); - } - return cls; - } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java index 920bade18..f625952ec 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java @@ -112,11 +112,6 @@ public class DeployBeanDescriptor { private List compoundUniqueConstraints; - /** - * Extra deployment attributes. - */ - private HashMap extraAttrMap = new HashMap(); - /** * The base database table. */ @@ -136,7 +131,7 @@ public class DeployBeanDescriptor { private Class beanType; private List persistControllers = new ArrayList(2); - private List> persistListeners = new ArrayList>(2); + private List persistListeners = new ArrayList(2); private List queryAdapters = new ArrayList(2); private CacheOptions cacheOptions = new CacheOptions(); @@ -445,13 +440,13 @@ public class DeployBeanDescriptor { /** * Return the BeanPersistListener (could be a chain of them, 1 or null). */ - public BeanPersistListener getPersistListener() { + public BeanPersistListener getPersistListener() { if (persistListeners.size() == 0) { return null; } else if (persistListeners.size() == 1) { return persistListeners.get(0); } else { - return new ChainedBeanPersistListener(persistListeners); + return new ChainedBeanPersistListener(persistListeners); } } @@ -472,7 +467,7 @@ public class DeployBeanDescriptor { persistControllers.add(controller); } - public void addPersistListener(BeanPersistListener listener) { + public void addPersistListener(BeanPersistListener listener) { persistListeners.add(listener); } @@ -542,29 +537,6 @@ public class DeployBeanDescriptor { return propMap.get(propName); } - public Map getExtraAttributeMap() { - return extraAttrMap; - } - - /** - * Get a named extra attribute. - */ - public String getExtraAttribute(String key) { - return (String) extraAttrMap.get(key); - } - - /** - * Set an extra attribute with a given name. - * - * @param key - * the name of the extra attribute - * @param value - * the value of the extra attribute - */ - public void setExtraAttribute(String key, String value) { - extraAttrMap.put(key, value); - } - /** * Return the bean class name this descriptor is used for. *

diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanPersistIds.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanPersistIds.java index ceb40920e..57626e88c 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanPersistIds.java +++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanPersistIds.java @@ -246,7 +246,7 @@ public class BeanPersistIds implements Serializable { */ public void notifyCacheAndListener() { - BeanPersistListener listener = beanDescriptor.getPersistListener(); + BeanPersistListener listener = beanDescriptor.getPersistListener(); // any change invalidates the query cache beanDescriptor.queryCacheClear(); diff --git a/src/test/java/com/avaje/tests/basic/TestExplicitInsert.java b/src/test/java/com/avaje/tests/basic/TestExplicitInsert.java index cab07c774..e6277344e 100644 --- a/src/test/java/com/avaje/tests/basic/TestExplicitInsert.java +++ b/src/test/java/com/avaje/tests/basic/TestExplicitInsert.java @@ -2,6 +2,7 @@ package com.avaje.tests.basic; import java.util.List; +import com.avaje.tests.model.basic.MyEBasicConfigStartup; import org.junit.Assert; import org.junit.Test; @@ -10,10 +11,16 @@ import com.avaje.ebean.Ebean; import com.avaje.ebean.EbeanServer; import com.avaje.tests.model.basic.EBasic; +import static org.junit.Assert.assertEquals; + public class TestExplicitInsert extends BaseTestCase { @Test - public void test() { + public void test() throws InterruptedException { + + Thread.sleep(100); + + MyEBasicConfigStartup.resetCounters(); EBasic b = new EBasic(); b.setName("exp insert"); @@ -34,9 +41,22 @@ public class TestExplicitInsert extends BaseTestCase { Assert.assertNotNull(b2.getId()); Assert.assertTrue(!b.getId().equals(b2.getId())); - List list = server.find(EBasic.class).where().in("id",b.getId(), b2.getId()).findList(); + List list = server.find(EBasic.class).where().in("id", b.getId(), b2.getId()).findList(); - Assert.assertEquals(2, list.size()); + assertEquals(2, list.size()); + + b2.setName("do an update"); + server.save(b2); + + server.delete(b); + server.delete(b2); + + // just sleep a little to allow the background thread to fire + Thread.sleep(100); + + assertEquals(2, MyEBasicConfigStartup.insertCount.get()); + assertEquals(1, MyEBasicConfigStartup.updateCount.get()); + assertEquals(2, MyEBasicConfigStartup.deleteCount.get()); } } diff --git a/src/test/java/com/avaje/tests/model/basic/MyEBasicConfigStartup.java b/src/test/java/com/avaje/tests/model/basic/MyEBasicConfigStartup.java index 385c412d5..2f5b70268 100644 --- a/src/test/java/com/avaje/tests/model/basic/MyEBasicConfigStartup.java +++ b/src/test/java/com/avaje/tests/model/basic/MyEBasicConfigStartup.java @@ -2,15 +2,23 @@ package com.avaje.tests.model.basic; import java.util.HashSet; import java.util.Set; +import java.util.concurrent.atomic.AtomicLong; import com.avaje.ebean.config.ServerConfig; -import com.avaje.ebean.event.BeanPersistListener; -import com.avaje.ebean.event.BulkTableEvent; -import com.avaje.ebean.event.BulkTableEventListener; -import com.avaje.ebean.event.ServerConfigStartup; +import com.avaje.ebean.event.*; public class MyEBasicConfigStartup implements ServerConfigStartup { + public static AtomicLong insertCount = new AtomicLong(); + public static AtomicLong updateCount = new AtomicLong(); + public static AtomicLong deleteCount = new AtomicLong(); + + public static void resetCounters() { + insertCount.set(0); + updateCount.set(0); + deleteCount.set(0); + } + public void onStart(ServerConfig serverConfig) { serverConfig.add(new EbasicPersistList()); @@ -35,32 +43,31 @@ public class MyEBasicConfigStartup implements ServerConfigStartup { } - public static class EbasicPersistList implements BeanPersistListener { + public static class EbasicPersistList extends AbstractBeanPersistListener { - public boolean inserted(EBasic bean) { - System.out.println("-- EBasic inserted " + bean.getId()); + @Override + public boolean isRegisterFor(Class cls) { + return EBasic.class.isAssignableFrom(cls); + } + + public boolean inserted(Object bean) { + insertCount.incrementAndGet(); + System.out.println("-- EBasic inserted " + ((EBasic)bean).getId()); return false; } - public boolean updated(EBasic bean, Set updatedProperties) { - System.out.println("-- EBasic updated " + bean.getId()+" updatedProperties: "+updatedProperties); + public boolean updated(Object bean, Set updatedProperties) { + updateCount.incrementAndGet(); + System.out.println("-- EBasic updated " + ((EBasic)bean).getId()+" updatedProperties: "+updatedProperties); return false; } - public boolean deleted(EBasic bean) { - System.out.println("-- EBasic deleted " + bean.getId()); + public boolean deleted(Object bean) { + deleteCount.incrementAndGet(); + System.out.println("-- EBasic deleted " + ((EBasic)bean).getId()); return false; } - public void remoteInsert(Object id) { - } - - public void remoteUpdate(Object id) { - } - - public void remoteDelete(Object id) { - } - } }