package io.ebean.bean; import io.ebean.Ebean; import io.ebean.ValuePair; import java.util.Arrays; import javax.persistence.EntityNotFoundException; import javax.persistence.PersistenceException; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.Serializable; import java.math.BigDecimal; import java.net.URL; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; /** * This is the object added to every entity bean using byte code enhancement. * <p> * This provides the mechanisms to support deferred fetching of reference beans * and oldValues generation for concurrency checking. * </p> */ public final class EntityBeanIntercept implements Serializable { private static final long serialVersionUID = -3664031775464862649L; private static final int STATE_NEW = 0; private static final int STATE_REFERENCE = 1; private static final int STATE_LOADED = 2; private transient NodeUsageCollector nodeUsageCollector; private transient PropertyChangeSupport pcs; private transient PersistenceContext persistenceContext; private transient BeanLoader beanLoader; private transient PreGetterCallback preGetterCallback; private String ebeanServerName; /** * The actual entity bean that 'owns' this intercept. */ private final EntityBean owner; private EntityBean embeddedOwner; private int embeddedOwnerIndex; /** * One of NEW, REF, UPD. */ private int state; private boolean readOnly; private boolean dirty; /** * Flag set to disable lazy loading - typically for SQL "report" type entity beans. */ private boolean disableLazyLoad; /** * Flag set when lazy loading failed due to the underlying bean being deleted in the DB. */ private boolean lazyLoadFailure; /** * Used when a bean is partially filled. */ private final boolean[] loadedProps; private boolean fullyLoadedBean; /** * Set of changed properties. */ private boolean[] changedProps; /** * Flags indicating if a property is a dirty embedded bean. Used to distingush * between an embedded bean being completely overwritten and one of its * embedded properties being made dirty. */ private boolean[] embeddedDirty; private Object[] origValues; private int lazyLoadProperty = -1; private Object ownerId; /** * Create a intercept with a given entity. * <p> * Refer to agent ProxyConstructor. * </p> */ public EntityBeanIntercept(Object ownerBean) { this.owner = (EntityBean) ownerBean; this.loadedProps = new boolean[owner._ebean_getPropertyNames().length]; } /** * Return the 'owning' entity bean. */ public EntityBean getOwner() { return owner; } /** * Return the persistenceContext. */ public PersistenceContext getPersistenceContext() { return persistenceContext; } /** * Set the persistenceContext. */ public void setPersistenceContext(PersistenceContext persistenceContext) { this.persistenceContext = persistenceContext; } /** * Add a property change listener for this entity bean. */ public void addPropertyChangeListener(PropertyChangeListener listener) { if (pcs == null) { pcs = new PropertyChangeSupport(owner); } pcs.addPropertyChangeListener(listener); } /** * Add a property change listener for this entity bean for a specific * property. */ public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { if (pcs == null) { pcs = new PropertyChangeSupport(owner); } pcs.addPropertyChangeListener(propertyName, listener); } /** * Remove a property change listener for this entity bean. */ public void removePropertyChangeListener(PropertyChangeListener listener) { if (pcs != null) { pcs.removePropertyChangeListener(listener); } } /** * Remove a property change listener for this entity bean for a specific * property. */ public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { if (pcs != null) { pcs.removePropertyChangeListener(propertyName, listener); } } /** * Turn on profile collection. */ public void setNodeUsageCollector(NodeUsageCollector usageCollector) { this.nodeUsageCollector = usageCollector; } /** * Return the owning bean for an embedded bean. */ public Object getEmbeddedOwner() { return embeddedOwner; } /** * Return the property index (for the parent) of this embedded bean. */ public int getEmbeddedOwnerIndex() { return embeddedOwnerIndex; } /** * Clear the getter callback. */ public void clearGetterCallback() { this.preGetterCallback = null; } /** * Register the callback to be triggered when getter is called. * This is used primarily to automatically flush the JDBC batch. */ public void registerGetterCallback(PreGetterCallback getterCallback) { this.preGetterCallback = getterCallback; } /** * Set the embedded beans owning bean. */ public void setEmbeddedOwner(EntityBean parentBean, int embeddedOwnerIndex) { this.embeddedOwner = parentBean; this.embeddedOwnerIndex = embeddedOwnerIndex; } /** * Set the BeanLoader with PersistenceContext. */ public void setBeanLoader(BeanLoader beanLoader, PersistenceContext ctx) { this.beanLoader = beanLoader; this.persistenceContext = ctx; this.ebeanServerName = beanLoader.getName(); } /** * Set the BeanLoader. */ public void setBeanLoader(BeanLoader beanLoader) { this.beanLoader = beanLoader; this.ebeanServerName = beanLoader.getName(); } public boolean isFullyLoadedBean() { return fullyLoadedBean; } public void setFullyLoadedBean(boolean fullyLoadedBean) { this.fullyLoadedBean = fullyLoadedBean; } /** * Check each property to see if the bean is partially loaded. */ public boolean isPartial() { for (boolean loadedProp : loadedProps) { if (!loadedProp) { return true; } } return false; } /** * Return true if this bean has been directly modified (it has oldValues) or * if any embedded beans are either new or dirty (and hence need saving). */ public boolean isDirty() { return dirty; } /** * Called by an embedded bean onto its owner. */ public void setEmbeddedDirty(int embeddedProperty) { this.dirty = true; setEmbeddedPropertyDirty(embeddedProperty); } public void setDirty(boolean dirty) { this.dirty = dirty; } /** * Return true if this entity bean is new and not yet saved. */ public boolean isNew() { return state == STATE_NEW; } /** * Return true if the entity bean is new or dirty (and should be saved). */ public boolean isNewOrDirty() { return isNew() || isDirty(); } /** * Return true if only the Id property has been loaded. */ public boolean hasIdOnly(int idIndex) { for (int i = 0; i < loadedProps.length; i++) { if (i == idIndex) { if (!loadedProps[i]) return false; } else if (loadedProps[i]) { return false; } } return true; } /** * Return true if the entity is a reference. */ public boolean isReference() { return state == STATE_REFERENCE; } /** * Set this as a reference object. */ public void setReference(int idPos) { state = STATE_REFERENCE; if (idPos > -1) { // For cases where properties are set on constructor // set every non Id property to unloaded (for lazy loading) for (int i = 0; i < loadedProps.length; i++) { if (i != idPos) { loadedProps[i] = false; } } } } /** * Return true if the bean should be treated as readOnly. If a setter method * is called when it is readOnly an Exception is thrown. */ public boolean isReadOnly() { return readOnly; } /** * Set the readOnly status. If readOnly then calls to setter methods through * an exception. */ public void setReadOnly(boolean readOnly) { this.readOnly = readOnly; } /** * Return true if the entity has been loaded. */ public boolean isLoaded() { return state == STATE_LOADED; } /** * Set the bean into NEW state. */ public void setNew() { this.state = STATE_NEW; } /** * Set the loaded state to true. * <p> * Calls to setter methods after the bean is loaded can result in 'Old Values' * being created to support ConcurrencyMode.ALL * </p> * <p> * Worth noting that this is also set after a insert/update. By doing so it * 'resets' the bean for making further changes and saving again. * </p> */ public void setLoaded() { this.state = STATE_LOADED; this.owner._ebean_setEmbeddedLoaded(); this.lazyLoadProperty = -1; this.origValues = null; this.changedProps = null; this.dirty = false; } /** * When finished loading for lazy or refresh on an already partially populated * bean. */ public void setLoadedLazy() { this.state = STATE_LOADED; this.lazyLoadProperty = -1; } /** * Set lazy load failure flag. */ public void setLazyLoadFailure(Object ownerId) { this.lazyLoadFailure = true; this.ownerId = ownerId; } /** * Return true if the bean is marked as having failed lazy loading. */ public boolean isLazyLoadFailure() { return lazyLoadFailure; } /** * Return true if lazy loading is disabled. */ public boolean isDisableLazyLoad() { return disableLazyLoad; } /** * Set true to turn off lazy loading. * <p> * Typically used to disable lazy loading on SQL based report beans. * </p> */ public void setDisableLazyLoad(boolean disableLazyLoad) { this.disableLazyLoad = disableLazyLoad; } /** * Set the loaded status for the embedded bean. */ public void setEmbeddedLoaded(Object embeddedBean) { if (embeddedBean instanceof EntityBean) { EntityBean eb = (EntityBean) embeddedBean; eb._ebean_getIntercept().setLoaded(); } } /** * Return true if the embedded bean is new or dirty and hence needs saving. */ public boolean isEmbeddedNewOrDirty(Object embeddedBean) { if (embeddedBean == null) { // if it was previously set then the owning bean would // have oldValues containing the previous embedded bean return false; } if (embeddedBean instanceof EntityBean) { return ((EntityBean) embeddedBean)._ebean_getIntercept().isNewOrDirty(); } else { // non-enhanced so must assume it is new and needs to be saved return true; } } /** * Return the original value that was changed via an update. */ public Object getOrigValue(int propertyIndex) { if (origValues == null) { return null; } return origValues[propertyIndex]; } /** * Finds the index position of a given property. Returns -1 if the property * can not be found. */ public int findProperty(String propertyName) { String[] names = owner._ebean_getPropertyNames(); for (int i = 0; i < names.length; i++) { if (names[i].equals(propertyName)) { return i; } } return -1; } /** * Return the property name for the given property. */ public String getProperty(int propertyIndex) { if (propertyIndex == -1) { return null; } return owner._ebean_getPropertyName(propertyIndex); } /** * Return the number of properties.s */ public int getPropertyLength() { return owner._ebean_getPropertyNames().length; } /** * Set the loaded state of the property given it's name. */ public void setPropertyLoaded(String propertyName, boolean loaded) { int position = findProperty(propertyName); if (position == -1) { throw new IllegalArgumentException("Property " + propertyName + " not found"); } loadedProps[position] = loaded; } /** * Set the property to be treated as unloaded. Used for properties initialised in default * constructor. */ public void setPropertyUnloaded(int propertyIndex) { loadedProps[propertyIndex] = false; } /** * Set the property to be loaded. */ public void setLoadedProperty(int propertyIndex) { loadedProps[propertyIndex] = true; } /** * Return true if the property is loaded. */ public boolean isLoadedProperty(int propertyIndex) { return loadedProps[propertyIndex]; } /** * Return true if the property is considered changed. */ public boolean isChangedProperty(int propertyIndex) { return (changedProps != null && changedProps[propertyIndex]); } /** * Return true if the property was changed or if it is embedded and one of its * embedded properties is dirty. */ public boolean isDirtyProperty(int propertyIndex) { return (changedProps != null && changedProps[propertyIndex] || embeddedDirty != null && embeddedDirty[propertyIndex]); } /** * Explicitly mark a property as having been changed. */ public void markPropertyAsChanged(int propertyIndex) { setChangedProperty(propertyIndex); setDirty(true); } public void setChangedProperty(int propertyIndex) { if (changedProps == null) { changedProps = new boolean[owner._ebean_getPropertyNames().length]; } changedProps[propertyIndex] = true; } /** * Set that an embedded bean has had one of its properties changed. */ private void setEmbeddedPropertyDirty(int propertyIndex) { if (embeddedDirty == null) { embeddedDirty = new boolean[owner._ebean_getPropertyNames().length]; } embeddedDirty[propertyIndex] = true; } private void setOriginalValue(int propertyIndex, Object value) { if (origValues == null) { origValues = new Object[owner._ebean_getPropertyNames().length]; } if (origValues[propertyIndex] == null) { origValues[propertyIndex] = value; } } /** * For forced update on a 'New' bean set all the loaded properties to changed. */ public void setNewBeanForUpdate() { if (changedProps == null) { changedProps = new boolean[owner._ebean_getPropertyNames().length]; } for (int i = 0; i < loadedProps.length; i++) { if (loadedProps[i]) { changedProps[i] = true; } } setDirty(true); } /** * Return the set of property names for a partially loaded bean. */ public Set<String> getLoadedPropertyNames() { if (fullyLoadedBean) { return null; } Set<String> props = new LinkedHashSet<>(); for (int i = 0; i < loadedProps.length; i++) { if (loadedProps[i]) { props.add(getProperty(i)); } } return props; } /** * Return the array of flags indicating the dirty properties. */ public boolean[] getDirtyProperties() { int len = getPropertyLength(); boolean[] dirties = new boolean[len]; for (int i = 0; i < len; i++) { if (changedProps != null && changedProps[i]) { dirties[i] = true; } else if (embeddedDirty != null && embeddedDirty[i]) { // an embedded property has been changed - recurse dirties[i] = true; } } return dirties; } /** * Return the set of dirty properties. */ public Set<String> getDirtyPropertyNames() { Set<String> props = new LinkedHashSet<>(); addDirtyPropertyNames(props, null); return props; } /** * Recursively add dirty properties. */ public void addDirtyPropertyNames(Set<String> props, String prefix) { int len = getPropertyLength(); for (int i = 0; i < len; i++) { if (changedProps != null && changedProps[i]) { // the property has been changed on this bean String propName = (prefix == null ? getProperty(i) : prefix + getProperty(i)); props.add(propName); } else if (embeddedDirty != null && embeddedDirty[i]) { // an embedded property has been changed - recurse EntityBean embeddedBean = (EntityBean) owner._ebean_getField(i); embeddedBean._ebean_getIntercept().addDirtyPropertyNames(props, getProperty(i) + "."); } } } /** * Return true if any of the given property names are dirty. */ public boolean hasDirtyProperty(Set<String> propertyNames) { String[] names = owner._ebean_getPropertyNames(); int len = getPropertyLength(); for (int i = 0; i < len; i++) { if (changedProps != null && changedProps[i]) { // the property has been changed on this bean if (propertyNames.contains(names[i])) { return true; } } else if (embeddedDirty != null && embeddedDirty[i]) { if (propertyNames.contains(names[i])) { return true; } } } return false; } /** * Return a map of dirty properties with their new and old values. */ public Map<String, ValuePair> getDirtyValues() { Map<String, ValuePair> dirtyValues = new LinkedHashMap<>(); addDirtyPropertyValues(dirtyValues, null); return dirtyValues; } /** * Recursively add dirty properties. */ public void addDirtyPropertyValues(Map<String, ValuePair> dirtyValues, String prefix) { int len = getPropertyLength(); for (int i = 0; i < len; i++) { if (changedProps != null && changedProps[i]) { // the property has been changed on this bean String propName = (prefix == null ? getProperty(i) : prefix + getProperty(i)); Object newVal = owner._ebean_getField(i); Object oldVal = getOrigValue(i); dirtyValues.put(propName, new ValuePair(newVal, oldVal)); } else if (embeddedDirty != null && embeddedDirty[i]) { // an embedded property has been changed - recurse EntityBean embeddedBean = (EntityBean) owner._ebean_getField(i); embeddedBean._ebean_getIntercept().addDirtyPropertyValues(dirtyValues, getProperty(i) + "."); } } } /** * Return a dirty property hash taking into account embedded beans. */ public StringBuilder getDirtyPropertyKey() { StringBuilder sb = new StringBuilder(); addDirtyPropertyKey(sb); return sb; } /** * Add and return a dirty property hash recursing into embedded beans. */ private void addDirtyPropertyKey(StringBuilder sb) { int len = getPropertyLength(); for (int i = 0; i < len; i++) { if (changedProps != null && changedProps[i]) { sb.append(i).append(','); } else if (embeddedDirty != null && embeddedDirty[i]) { // an embedded property has been changed - recurse EntityBean embeddedBean = (EntityBean) owner._ebean_getField(i); sb.append(i).append('['); embeddedBean._ebean_getIntercept().addDirtyPropertyKey(sb); sb.append(']'); } } } /** * Return a loaded property hash. */ public StringBuilder getLoadedPropertyKey() { StringBuilder sb = new StringBuilder(); int len = getPropertyLength(); for (int i = 0; i < len; i++) { if (isLoadedProperty(i)) { sb.append(i).append(','); } } return sb; } /** * Return the set of property names for changed properties. */ public boolean[] getChanged() { return changedProps; } public boolean[] getLoaded() { return loadedProps; } /** * Return the index of the property that triggered the lazy load. */ public int getLazyLoadPropertyIndex() { return lazyLoadProperty; } /** * Return the property that triggered the lazy load. */ public String getLazyLoadProperty() { return getProperty(lazyLoadProperty); } /** * Load the bean when it is a reference. */ protected void loadBean(int loadProperty) { synchronized (this) { if (beanLoader == null) { BeanLoader serverLoader = (BeanLoader) Ebean.getServer(ebeanServerName); if (serverLoader == null) { throw new PersistenceException("Server [" + ebeanServerName + "] was not found?"); } // For stand alone reference bean or after deserialisation lazy load // using the ebeanServer. Synchronise only on the bean. loadBeanInternal(loadProperty, serverLoader); return; } } synchronized (beanLoader) { // Lazy loading using LoadBeanContext which supports batch loading // Synchronise on the beanLoader (a 'node' of the LoadBeanContext 'tree') loadBeanInternal(loadProperty, beanLoader); } } /** * Invoke the lazy loading. This method is synchronised externally. */ private void loadBeanInternal(int loadProperty, BeanLoader loader) { if (loadedProps == null || loadedProps[loadProperty]) { // race condition where multiple threads calling preGetter concurrently return; } if (lazyLoadFailure) { // failed when batch lazy loaded by another bean in the batch throw new EntityNotFoundException("Lazy loading failed on type:" + owner.getClass().getName() + " id:" + ownerId + " - Bean has been deleted"); } if (lazyLoadProperty == -1) { lazyLoadProperty = loadProperty; if (nodeUsageCollector != null) { nodeUsageCollector.setLoadProperty(getProperty(lazyLoadProperty)); } loader.loadBean(this); if (lazyLoadFailure) { // failed when lazy loading this bean throw new EntityNotFoundException("Lazy loading failed on type:" + owner.getClass().getName() + " id:" + ownerId + " - Bean has been deleted."); } // bean should be loaded and intercepting now. setLoaded() has // been called by the lazy loading mechanism } } /** * Helper method to check if two objects are equal. */ @SuppressWarnings({"unchecked", "rawtypes"}) protected boolean areEqual(Object obj1, Object obj2) { if (obj1 == null) { return (obj2 == null); } if (obj2 == null) { return false; } if (obj1 == obj2) { return true; } if (obj1 instanceof BigDecimal) { // Use comparable for BigDecimal as equals // uses scale in comparison... if (obj2 instanceof BigDecimal) { Comparable com1 = (Comparable) obj1; return (com1.compareTo(obj2) == 0); } else { return false; } } if (obj1 instanceof URL) { // use the string format to determine if dirty return obj1.toString().equals(obj2.toString()); } return obj1.equals(obj2); } /** * Called when a BeanCollection is initialised automatically. */ public void initialisedMany(int propertyIndex) { loadedProps[propertyIndex] = true; } private void preGetterCallback() { if (preGetterCallback != null) { preGetterCallback.preGetterTrigger(); } } /** * Called prior to Id property getter. */ public void preGetId() { preGetterCallback(); } /** * Method that is called prior to a getter method on the actual entity. */ public void preGetter(int propertyIndex) { preGetterCallback(); if (state == STATE_NEW || disableLazyLoad) { return; } if (!isLoadedProperty(propertyIndex)) { loadBean(propertyIndex); } if (nodeUsageCollector != null) { nodeUsageCollector.addUsed(getProperty(propertyIndex)); } } /** * Called for "enhancement" postSetter processing. This is around a PUTFIELD * so no need to check the newValue afterwards. */ public void postSetter(PropertyChangeEvent event) { if (pcs != null && event != null) { pcs.firePropertyChange(event); } } /** * Called for "subclassed" postSetter processing. Here the newValue has to be * re-fetched (and passed into this method) in case there is code inside the * setter that further mutates the value. */ public void postSetter(PropertyChangeEvent event, Object newValue) { if (pcs != null && event != null) { if (newValue != null && newValue.equals(event.getNewValue())) { pcs.firePropertyChange(event); } else { pcs.firePropertyChange(event.getPropertyName(), event.getOldValue(), newValue); } } } /** * OneToMany and ManyToMany don't have any interception so just check for * PropertyChangeSupport. */ public PropertyChangeEvent preSetterMany(boolean interceptField, int propertyIndex, Object oldValue, Object newValue) { if (readOnly) { throw new IllegalStateException("This bean is readOnly"); } setLoadedProperty(propertyIndex); // Bean itself not considered dirty when many changed if (pcs != null) { return new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue); } else { return null; } } private void setChangedPropertyValue(int propertyIndex, boolean setDirtyState, Object origValue) { if (readOnly) { throw new IllegalStateException("This bean is readOnly"); } setChangedProperty(propertyIndex); if (setDirtyState) { setOriginalValue(propertyIndex, origValue); if (!dirty) { dirty = true; if (embeddedOwner != null) { // Cascade dirty state from Embedded bean to parent bean embeddedOwner._ebean_getIntercept().setEmbeddedDirty(embeddedOwnerIndex); } if (nodeUsageCollector != null) { nodeUsageCollector.setModified(); } } } } /** * Check to see if the values are not equal. If they are not equal then create * the old values for use with ConcurrencyMode.ALL. */ public PropertyChangeEvent preSetter(boolean intercept, int propertyIndex, Object oldValue, Object newValue) { if (state == STATE_NEW) { setLoadedProperty(propertyIndex); } else if (!areEqual(oldValue, newValue)) { setChangedPropertyValue(propertyIndex, intercept, oldValue); } else { return null; } return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue); } /** * Check for primitive boolean. */ public PropertyChangeEvent preSetter(boolean intercept, int propertyIndex, boolean oldValue, boolean newValue) { if (state == STATE_NEW) { setLoadedProperty(propertyIndex); } else if (oldValue != newValue) { setChangedPropertyValue(propertyIndex, intercept, oldValue); } else { return null; } return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue); } /** * Check for primitive int. */ public PropertyChangeEvent preSetter(boolean intercept, int propertyIndex, int oldValue, int newValue) { if (state == STATE_NEW) { setLoadedProperty(propertyIndex); } else if (oldValue != newValue) { setChangedPropertyValue(propertyIndex, intercept, oldValue); } else { return null; } return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue); } /** * long. */ public PropertyChangeEvent preSetter(boolean intercept, int propertyIndex, long oldValue, long newValue) { if (state == STATE_NEW) { setLoadedProperty(propertyIndex); } else if (oldValue != newValue) { setChangedPropertyValue(propertyIndex, intercept, oldValue); } else { return null; } return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue); } /** * double. */ public PropertyChangeEvent preSetter(boolean intercept, int propertyIndex, double oldValue, double newValue) { if (state == STATE_NEW) { setLoadedProperty(propertyIndex); } else if (oldValue != newValue) { setChangedPropertyValue(propertyIndex, intercept, oldValue); } else { return null; } return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue); } /** * float. */ public PropertyChangeEvent preSetter(boolean intercept, int propertyIndex, float oldValue, float newValue) { if (state == STATE_NEW) { setLoadedProperty(propertyIndex); } else if (oldValue != newValue) { setChangedPropertyValue(propertyIndex, intercept, oldValue); } else { return null; } return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue); } /** * short. */ public PropertyChangeEvent preSetter(boolean intercept, int propertyIndex, short oldValue, short newValue) { if (state == STATE_NEW) { setLoadedProperty(propertyIndex); } else if (oldValue != newValue) { setChangedPropertyValue(propertyIndex, intercept, oldValue); } else { return null; } return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue); } /** * char. */ public PropertyChangeEvent preSetter(boolean intercept, int propertyIndex, char oldValue, char newValue) { if (state == STATE_NEW) { setLoadedProperty(propertyIndex); } else if (oldValue != newValue) { setChangedPropertyValue(propertyIndex, intercept, oldValue); } else { return null; } return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue); } /** * byte. */ public PropertyChangeEvent preSetter(boolean intercept, int propertyIndex, byte oldValue, byte newValue) { if (state == STATE_NEW) { setLoadedProperty(propertyIndex); } else if (oldValue != newValue) { setChangedPropertyValue(propertyIndex, intercept, oldValue); } else { return null; } return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue); } /** * char[]. */ public PropertyChangeEvent preSetter(boolean intercept, int propertyIndex, char[] oldValue, char[] newValue) { if (state == STATE_NEW) { setLoadedProperty(propertyIndex); } else if (!Arrays.equals(oldValue, newValue)) { setChangedPropertyValue(propertyIndex, intercept, oldValue); } else { return null; } return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue); } /** * byte[]. */ public PropertyChangeEvent preSetter(boolean intercept, int propertyIndex, byte[] oldValue, byte[] newValue) { if (state == STATE_NEW) { setLoadedProperty(propertyIndex); } else if (!Arrays.equals(oldValue, newValue)) { setChangedPropertyValue(propertyIndex, intercept, oldValue); } else { return null; } return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue); } }