Skip to main content
summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorBrian Vosburgh2016-07-15 15:25:29 +0000
committerBrian Vosburgh2017-05-18 22:37:56 +0000
commit8ff9fb95c56ff9fdc5bc534e0a78e3933e090241 (patch)
treeba23e1ccee991d07faf2103c04da68b88570dcc1 /common
parent595e54e3513c560f3ece0e4a47049334a8a5fee3 (diff)
downloadwebtools.dali-8ff9fb95c56ff9fdc5bc534e0a78e3933e090241.tar.gz
webtools.dali-8ff9fb95c56ff9fdc5bc534e0a78e3933e090241.tar.xz
webtools.dali-8ff9fb95c56ff9fdc5bc534e0a78e3933e090241.zip
refactor BufferedPVM
Diffstat (limited to 'common')
-rw-r--r--common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/properties/JptProjectPropertiesPage.java13
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/AbstractPropertyValueModel.java125
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/BasePluggablePropertyValueModel.java2
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/BufferedModifiablePropertyValueModel.java398
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/BufferedPropertyValueModelAdapter.java349
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/PropertyValueModelTools.java30
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/PropertyValueModelWrapper.java124
-rw-r--r--common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/BufferedModifiablePropertyValueModelTests.java504
-rw-r--r--common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/BufferedPropertyValueModelTests.java597
-rw-r--r--common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/JptCommonUtilityModelValueTests.java2
10 files changed, 985 insertions, 1159 deletions
diff --git a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/properties/JptProjectPropertiesPage.java b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/properties/JptProjectPropertiesPage.java
index df59dc5316..78fc9c36d1 100644
--- a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/properties/JptProjectPropertiesPage.java
+++ b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/properties/JptProjectPropertiesPage.java
@@ -28,7 +28,8 @@ import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jpt.common.ui.internal.plugin.JptCommonUiPlugin;
import org.eclipse.jpt.common.utility.internal.ArrayTools;
import org.eclipse.jpt.common.utility.internal.ObjectTools;
-import org.eclipse.jpt.common.utility.internal.model.value.BufferedModifiablePropertyValueModel;
+import org.eclipse.jpt.common.utility.internal.model.value.BufferedPropertyValueModelAdapter;
+import org.eclipse.jpt.common.utility.internal.model.value.PropertyValueModelTools;
import org.eclipse.jpt.common.utility.internal.model.value.SimplePropertyValueModel;
import org.eclipse.jpt.common.utility.model.Model;
import org.eclipse.jpt.common.utility.model.listener.AbstractChangeListener;
@@ -65,7 +66,7 @@ public abstract class JptProjectPropertiesPage
protected volatile boolean engaged = false;
protected final ModifiablePropertyValueModel<IProject> projectModel;
- protected final BufferedModifiablePropertyValueModel.Trigger trigger;
+ protected final BufferedPropertyValueModelAdapter.Trigger trigger;
protected final ChangeListener validationListener;
@@ -74,7 +75,7 @@ public abstract class JptProjectPropertiesPage
super();
this.projectModel = new SimplePropertyValueModel<>();
- this.trigger = new BufferedModifiablePropertyValueModel.Trigger();
+ this.trigger = PropertyValueModelTools.bufferedPropertyValueModelAdapterTrigger();
this.buildModels();
@@ -350,15 +351,15 @@ public abstract class JptProjectPropertiesPage
* Return whether any of the models are buffering a change.
*/
private boolean isBuffering() {
- for (BufferedModifiablePropertyValueModel<?> model : this.buildBufferedModels()) {
- if (model.isBuffering()) {
+ for (PropertyValueModel<Boolean> flag : this.buildBufferingFlags()) {
+ if (flag.getValue().booleanValue()) {
return true;
}
}
return false;
}
- protected abstract BufferedModifiablePropertyValueModel<?>[] buildBufferedModels();
+ protected abstract PropertyValueModel<Boolean>[] buildBufferingFlags();
@Override
protected void performDefaults() {
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/AbstractPropertyValueModel.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/AbstractPropertyValueModel.java
deleted file mode 100644
index aeb34de889..0000000000
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/AbstractPropertyValueModel.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2009, 2016 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.common.utility.internal.model.value;
-
-import org.eclipse.jpt.common.utility.internal.model.AbstractModel;
-import org.eclipse.jpt.common.utility.internal.model.ChangeSupport;
-import org.eclipse.jpt.common.utility.internal.model.SingleAspectChangeSupport;
-import org.eclipse.jpt.common.utility.model.listener.ChangeListener;
-import org.eclipse.jpt.common.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
-
-/**
- * This abstract class provides the infrastructure for "lazily" adding/removing
- * listeners to/from an underlying model as <em>property</em> change
- * listeners are added to/removed from itself.
- * Subclasses will need to engage and disengage the underlying model
- * appropriately and fire the appropriate <em>property</em>
- * change events.
- * <p>
- * Subclasses must implement the appropriate {@link PropertyValueModel}.
- * <p>
- * Subclasses must implement the following methods:<ul>
- * <li>{@link #engageModel()}<p>
- * implement this method to add the appropriate listener(s) to the
- * underlying model
- * <li>{@link #disengageModel()}<p>
- * implement this method to remove the appropriate listener(s) from the
- * underlying model
- * </ul>
- */
-public abstract class AbstractPropertyValueModel
- extends AbstractModel
-{
- // ********** constructor/initialization **********
-
- protected AbstractPropertyValueModel() {
- super();
- }
-
- @Override
- protected ChangeSupport buildChangeSupport() {
- return new SingleAspectChangeSupport(this, PropertyChangeListener.class, PropertyValueModel.VALUE);
- }
-
-
- // ********** listeners **********
-
- /**
- * Extend to start listening to the underlying model if necessary.
- */
- @Override
- public synchronized void addChangeListener(ChangeListener listener) {
- if (this.hasNoListeners()) {
- this.engageModel();
- }
- super.addChangeListener(listener);
- }
-
- /**
- * Extend to stop listening to the underlying model if necessary.
- */
- @Override
- public synchronized void removeChangeListener(ChangeListener listener) {
- super.removeChangeListener(listener);
- if (this.hasNoListeners()) {
- this.disengageModel();
- }
- }
-
- /**
- * Extend to start listening to the underlying model if necessary.
- */
- @Override
- public synchronized void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
- if (propertyName.equals(PropertyValueModel.VALUE) && this.hasNoListeners()) {
- this.engageModel();
- }
- super.addPropertyChangeListener(propertyName, listener);
- }
-
- /**
- * Extend to stop listening to the underlying model if necessary.
- */
- @Override
- public synchronized void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
- super.removePropertyChangeListener(propertyName, listener);
- if (propertyName.equals(PropertyValueModel.VALUE) && this.hasNoListeners()) {
- this.disengageModel();
- }
- }
-
- /**
- * Return whether the model has no property value listeners.
- */
- public boolean hasNoListeners() {
- return ! this.hasListeners();
- }
-
- /**
- * Return whether the model has any property value listeners.
- */
- public boolean hasListeners() {
- return this.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE);
- }
-
-
- // ********** subclass implementation **********
-
- /**
- * Engage the underlying model.
- */
- protected abstract void engageModel();
-
- /**
- * Stop listening to the underlying model.
- */
- protected abstract void disengageModel();
-}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/BasePluggablePropertyValueModel.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/BasePluggablePropertyValueModel.java
index 69538412e0..6b94a430d8 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/BasePluggablePropertyValueModel.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/BasePluggablePropertyValueModel.java
@@ -174,7 +174,7 @@ public abstract class BasePluggablePropertyValueModel<V, A extends BasePluggable
// ********** Adapter Listener **********
/**
- * Simple callback.
+ * Simple callback. Allows us to keep the callback method internal.
*/
/* CU private */ class AdapterListener
implements Adapter.Listener<V>
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/BufferedModifiablePropertyValueModel.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/BufferedModifiablePropertyValueModel.java
deleted file mode 100644
index 8dbd7b2f56..0000000000
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/BufferedModifiablePropertyValueModel.java
+++ /dev/null
@@ -1,398 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2012 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.common.utility.internal.model.value;
-
-import org.eclipse.jpt.common.utility.internal.ObjectTools;
-import org.eclipse.jpt.common.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.common.utility.model.listener.PropertyChangeAdapter;
-import org.eclipse.jpt.common.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
-import org.eclipse.jpt.common.utility.model.value.ModifiablePropertyValueModel;
-
-/**
- * A <code>BufferedModifiablePropertyValueModel</code> is used to hold a temporary
- * copy of the value
- * in another property value model (the "wrapped" value model). The application
- * can modify this temporary copy, ad nauseam; but the temporary copy is only
- * passed through to the "wrapped" value model when the trigger "accepts" the
- * buffered value. Alternatively, the application can "reset" the buffered value
- * to the original, "wrapped" value.
- * <p>
- * The trigger is another {@link PropertyValueModel} that holds a
- * {@link Boolean} and the application changes the trigger's value to
- * <code>true</code> on "accept", <code>false</code> on "reset".
- * <p>
- * Typically, in a dialog:<ul>
- * <li>pressing the "OK" button will trigger an "accept" and close the dialog
- * <li>pressing the "Cancel" button will simply close the dialog,
- * dropping the "buffered" values into the bit bucket
- * <li>pressing the "Apply" button will trigger an "accept" and leave the
- * dialog open
- * <li>pressing the "Restore" button will trigger a "reset" and leave the
- * dialog open
- * </ul>
- * A number of buffered property value models can wrap another set of
- * property aspect adapters that adapt the various aspects of a single
- * domain model. All the buffered property value models can be hooked to the
- * same trigger, and that trigger is controlled by the application, typically
- * via the "OK" button in a dialog.
- *
- * @param <V> the type of the model's value
- * @see PropertyAspectAdapter
- */
-public class BufferedModifiablePropertyValueModel<V>
- extends PropertyValueModelWrapper<V>
- implements ModifiablePropertyValueModel<V>
-{
- /**
- * We cache the value here until it is accepted and passed
- * through to the wrapped value model.
- */
- protected volatile V bufferedValue;
-
- /**
- * This is set to true when we are "accepting" the buffered value
- * and passing it through to the wrapped value model. This allows
- * us to ignore the property change event fired by the wrapped
- * value model.
- * (We can't stop listening to the wrapped value model, because
- * if we are the only listener that could "deactivate" the wrapped
- * value model.)
- */
- protected volatile boolean accepting;
-
- /**
- * This is the trigger that indicates whether the buffered value
- * should be accepted or reset.
- */
- protected final PropertyValueModel<Boolean> triggerModel;
-
- /** This listens to the trigger model. */
- protected final PropertyChangeListener triggerListener;
-
- /**
- * This flag indicates whether our buffered value has been assigned
- * a value and is possibly out of sync with the wrapped value.
- */
- protected volatile boolean buffering;
-
-
- // ********** constructor/initialization **********
-
- /**
- * Construct a buffered property value model with the specified wrapped
- * property value model and trigger model.
- */
- // TODO wrap the value model in a CachingPVMWrapper and get rid of accepting flag
- public BufferedModifiablePropertyValueModel(ModifiablePropertyValueModel<V> valueModel, PropertyValueModel<Boolean> triggerModel) {
- super(valueModel);
- if (triggerModel == null) {
- throw new NullPointerException();
- }
- this.triggerModel = triggerModel;
- this.bufferedValue = null;
- this.buffering = false;
- this.accepting = false;
- this.triggerListener = this.buildTriggerListener();
- }
-
- protected PropertyChangeListener buildTriggerListener() {
- return new TriggerListener();
- }
-
- protected class TriggerListener
- extends PropertyChangeAdapter
- {
- @Override
- public void propertyChanged(PropertyChangeEvent event) {
- BufferedModifiablePropertyValueModel.this.triggerChanged(event);
- }
- }
-
-
- // ********** value **********
-
- /**
- * If we are currently "buffering" a value, return that;
- * otherwise, return the wrapped value.
- */
- public V getValue() {
- return this.buffering ? this.bufferedValue : this.valueModel.getValue();
- }
-
- /**
- * Assign the new value to our "buffered" value.
- * It will be pushed to the wrapped value model
- * when the trigger is "accepted".
- */
- public void setValue(V value) {
- if (this.buffering) {
- if (ObjectTools.equals(value, this.valueModel.getValue())) {
- // the buffered value is being set back to the original value
- this.reset();
- } else {
- // the buffered value is being changed
- Object old = this.bufferedValue;
- this.bufferedValue = value;
- this.firePropertyChanged(VALUE, old, value);
- }
- } else {
- if (ObjectTools.equals(value, this.valueModel.getValue())) {
- // the buffered value is being set to the same value as the original value - ignore
- } else {
- // the buffered value is being set for the first time
- Object old = this.valueModel.getValue();
- this.bufferedValue = value;
- this.buffering = true;
- this.firePropertyChanged(VALUE, old, value);
- }
- }
- }
-
-
- // ********** PropertyValueModelWrapper extensions **********
-
- /**
- * Extend to engage the trigger model also.
- */
- @Override
- protected void engageModel() {
- super.engageModel();
- this.triggerModel.addPropertyChangeListener(VALUE, this.triggerListener);
- }
-
- /**
- * Extend to disengage the trigger model also.
- */
- @Override
- protected void disengageModel() {
- this.triggerModel.removePropertyChangeListener(VALUE, this.triggerListener);
- super.disengageModel();
- }
-
-
- // ********** behavior **********
-
- /**
- * If we are currently "accepting" the value (i.e passing it on to the
- * "wrapped" model), ignore change notifications, since we caused
- * them and our own listeners are already aware of the change.
- */
- @Override
- protected void wrappedValueChanged(PropertyChangeEvent event) {
- if ( ! this.accepting) {
- this.wrappedValueChanged_(event);
- }
- }
-
- /**
- * If we have a "buffered" value, check whether the "wrapped" value has
- * changed to be the same as the "buffered" value. If it has, stop "buffering";
- * if not, do nothing.
- * If we do not yet have a "buffered" value, simply propagate the
- * change notification with the buffered model as the source.
- */
- protected void wrappedValueChanged_(PropertyChangeEvent event) {
- if (this.buffering) {
- if (ObjectTools.equals(event.getNewValue(), this.bufferedValue)) {
- // the buffered value is being set back to the original value
- this.reset();
- } else {
- this.handleChangeConflict(event);
- }
- } else {
- this.firePropertyChanged(event.clone(this));
- }
- }
-
- /**
- * By default, if we have a "buffered" value and the "wrapped" value changes,
- * we simply ignore the new "wrapped" value and simply overlay it with the
- * "buffered" value if it is "accepted". ("Last One In Wins" concurrency model)
- * Subclasses can override this method to change that behavior with a
- * different concurrency model. For example, you could drop the "buffered" value
- * and replace it with the new "wrapped" value, or you could throw an
- * exception.
- */
- protected void handleChangeConflict(@SuppressWarnings("unused") PropertyChangeEvent event) {
- // the default is to do nothing
- }
-
- protected void triggerChanged(PropertyChangeEvent event) {
- this.triggerChanged(((Boolean) event.getNewValue()).booleanValue());
- }
-
- /**
- * The trigger changed:<ul>
- * <li>If it is now <code>true</code>, "accept" the buffered value and push
- * it to the wrapped value model.
- * <li>If it is now <code>false</code>, "reset" the buffered value to its
- * original value.
- * </ul>
- */
- protected void triggerChanged(boolean triggerValue) {
- // if nothing has been "buffered", we don't need to do anything:
- // nothing needs to be passed through; nothing needs to be reset;
- if (this.buffering) {
- if (triggerValue) {
- this.accept();
- } else {
- this.reset();
- }
- }
- }
-
- protected void accept() {
- // set the accepting flag so we ignore any events
- // fired by the wrapped value model
- this.accepting = true;
- try {
- this.getValueModel().setValue(this.bufferedValue);
- } finally {
- this.bufferedValue = null;
- this.buffering = false;
- // clear the flag once the "accept" is complete
- this.accepting = false;
- }
- }
-
- protected void reset() {
- // notify our listeners that our value has been reset
- Object old = this.bufferedValue;
- this.bufferedValue = null;
- this.buffering = false;
- this.firePropertyChanged(VALUE, old, this.valueModel.getValue());
- }
-
- @Override
- public void toString(StringBuilder sb) {
- sb.append(this.getValue());
- }
-
-
- // ********** misc **********
-
- /**
- * Return whether the buffered model is currently "buffering"
- * a value.
- */
- public boolean isBuffering() {
- return this.buffering;
- }
-
- /**
- * Our constructor accepts only a {@link ModifiablePropertyValueModel}{@code<T>}.
- */
- @SuppressWarnings("unchecked")
- protected ModifiablePropertyValueModel<V> getValueModel() {
- return (ModifiablePropertyValueModel<V>) this.valueModel;
- }
-
-
- // ********** trigger **********
-
- /**
- * <code>Trigger</code> is a special property value model that only maintains its
- * value (of <code>true</code> or <code>false</code>) during the change notification caused by
- * {@link #setValue(Object)}. In other words, a <code>Trigger</code>
- * only has a valid value when it is being set.
- */
- public static class Trigger
- extends SimplePropertyValueModel<Boolean>
- {
- /**
- * Construct a trigger with a null value.
- */
- public Trigger() {
- super();
- }
-
-
- // ********** ValueModel implementation **********
-
- /**
- * Extend so that this method can only be invoked during
- * change notification triggered by {@link #setValue(Object)}.
- */
- @Override
- public Boolean getValue() {
- if (this.value == null) {
- throw new IllegalStateException("The method Trigger.getValue() may only be called during change notification."); //$NON-NLS-1$
- }
- return this.value;
- }
-
- /**
- * Extend to reset the value to <code>null</code> once all the
- * listeners have been notified.
- */
- @Override
- public void setValue(Boolean value) {
- super.setValue(value);
- this.value = null;
- }
-
-
- // ********** convenience methods **********
-
- /**
- * Set the trigger's value:<ul>
- * <li><code>true</code> indicates "accept"
- * <li><code>false</code> indicates "reset"
- * </ul>
- */
- public void setValue(boolean value) {
- this.setValue(Boolean.valueOf(value));
- }
-
- /**
- * Return the trigger's value:<ul>
- * <li><code>true</code> indicates "accept"
- * <li><code>false</code> indicates "reset"
- * </ul>
- * This method can only be invoked during change notification.
- */
- public boolean booleanValue() {
- return this.getValue().booleanValue();
- }
-
- /**
- * Accept the trigger (i.e. set its value to <code>true</code>).
- */
- public void accept() {
- this.setValue(true);
- }
-
- /**
- * Return whether the trigger has been accepted
- * (i.e. its value was changed to <code>true</code>).
- * This method can only be invoked during change notification.
- */
- public boolean isAccepted() {
- return this.booleanValue();
- }
-
- /**
- * Reset the trigger (i.e. set its value to <code>false</code>).
- */
- public void reset() {
- this.setValue(false);
- }
-
- /**
- * Return whether the trigger has been reset
- * (i.e. its value was changed to <code>false</code>).
- * This method can only be invoked during change notification.
- */
- public boolean isReset() {
- return ! this.booleanValue();
- }
- }
-}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/BufferedPropertyValueModelAdapter.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/BufferedPropertyValueModelAdapter.java
new file mode 100644
index 0000000000..8ac19c8530
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/BufferedPropertyValueModelAdapter.java
@@ -0,0 +1,349 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2016 Oracle. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0, which accompanies this distribution
+ * and is available at http://www.eclipse.org/legal/epl-v10.html.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.jpt.common.utility.internal.model.value;
+
+import org.eclipse.jpt.common.utility.internal.ListenerList;
+import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.internal.model.ModelTools;
+import org.eclipse.jpt.common.utility.model.event.PropertyChangeEvent;
+import org.eclipse.jpt.common.utility.model.listener.PropertyChangeListener;
+import org.eclipse.jpt.common.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
+
+/**
+ * This adapter is used to hold a temporary copy of the value
+ * in another property value model (the <em>wrapped</em> value model). The application
+ * can modify this temporary copy, ad nauseam; but the temporary copy is only
+ * passed through to the <em>wrapped</em> value model when the trigger <em>accepts</em> the
+ * buffered value. Alternatively, the application can <em>reset</em> the buffered value
+ * to the original, <em>wrapped</em> value.
+ * <p>
+ * The trigger is an object that can be used to <em>accept</em> or <em>reset</em>
+ * the buffered value on one or more buffered value models.
+ * <p>
+ * Typically, in a dialog:<ul>
+ * <li>pressing the "OK" button will trigger an <em>accept</em> and close the dialog
+ * <li>pressing the "Cancel" button will simply close the dialog,
+ * dropping the <em>buffered</em> values into the bit bucket
+ * <li>pressing the "Apply" button will trigger an <em>accept</em> and leave the
+ * dialog open
+ * <li>pressing the "Restore" button will trigger a <em>reset</em> and leave the
+ * dialog open
+ * </ul>
+ * As an example: A number of buffered property value models can wrap another set of
+ * property aspect adapters that adapt the various aspects of a single
+ * domain model. All the buffered property value models can be hooked to the
+ * same trigger, and that trigger is controlled by the application, typically
+ * via the "OK" button in a dialog.
+ *
+ * @param <V> the type of the model's value
+ * @see PropertyAspectAdapter
+ */
+public class BufferedPropertyValueModelAdapter<V>
+ implements PluggableModifiablePropertyValueModel.Adapter<V>, PropertyChangeListener
+{
+ /**
+ * The <em>wrapped</em> model.
+ */
+ private final ModifiablePropertyValueModel<V> wrappedValueModel;
+
+ /**
+ * The cached value of {@link #wrappedValueModel}.
+ */
+ private volatile V wrappedValue;
+
+ /**
+ * The trigger that <em>accepts</em> or <em>resets</em> {@link #bufferedValue}.
+ */
+ private final Trigger trigger;
+ private final Trigger.Listener triggerListener;
+
+ /**
+ * The <em>real</em> adapter.
+ */
+ private final BasePluggablePropertyValueModel.Adapter.Listener<V> listener;
+
+ /**
+ * This flag indicates whether {@link #bufferedValue} has been assigned
+ * a value and is out of sync with {@link #wrappedValue}.
+ */
+ private final SimplePropertyValueModel<Boolean> bufferingModel;
+
+ /**
+ * We cache the value here until it is accepted and passed
+ * through to {@link #wrappedValueModel}.
+ */
+ private volatile V bufferedValue;
+
+
+ // ********** constructors **********
+
+ public BufferedPropertyValueModelAdapter(Factory<V> factory, BasePluggablePropertyValueModel.Adapter.Listener<V> listener) {
+ super();
+ if (factory == null) {
+ throw new NullPointerException();
+ }
+ this.wrappedValueModel = factory.wrappedValueModel;
+ this.trigger = factory.trigger;
+ this.triggerListener = this.buildTriggerListener();
+ this.bufferingModel = factory.bufferingModel;
+
+ if (listener == null) {
+ throw new NullPointerException();
+ }
+ this.listener = listener;
+ }
+
+ private Trigger.Listener buildTriggerListener() {
+ return new TriggerListener();
+ }
+
+ /* CU private */ class TriggerListener
+ implements Trigger.Listener
+ {
+ public void accept() {
+ BufferedPropertyValueModelAdapter.this.accept();
+ }
+ public void reset() {
+ BufferedPropertyValueModelAdapter.this.reset();
+ }
+ @Override
+ public String toString() {
+ return ObjectTools.toString(this);
+ }
+ }
+
+
+ // ********** PluggableModifiablePropertyValueModel.Adapter **********
+
+ public V getValue() {
+ return this.isBuffering() ? this.bufferedValue : this.wrappedValue;
+ }
+
+ public void setValue(V value) {
+ if (this.isBuffering()) {
+ if (ObjectTools.equals(value, this.wrappedValue)) {
+ // our value is being set back to the original wrapped value - stop buffering
+ this.bufferedValue = null;
+ this.setBuffering(false);
+ this.listener.valueChanged(this.wrappedValue);
+ } else {
+ // our (buffered) value is being changed
+ this.listener.valueChanged(this.bufferedValue = value);
+ }
+ } else {
+ if (ObjectTools.equals(value, this.wrappedValue)) {
+ // our value is being set to the same as the original wrapped value - ignore
+ } else {
+ // our value is being changed for the first time - start buffering
+ this.setBuffering(true);
+ this.listener.valueChanged(this.bufferedValue = value);
+ }
+ }
+ }
+
+ public void engageModel() {
+ this.wrappedValueModel.addPropertyChangeListener(PropertyValueModel.VALUE, this);
+ this.wrappedValue = this.wrappedValueModel.getValue();
+ this.trigger.addListener(this.triggerListener);
+ }
+
+ public void disengageModel() {
+ this.setBuffering(false);
+ this.bufferedValue = null;
+ this.trigger.removeListener(this.triggerListener);
+ this.wrappedValue = null;
+ this.wrappedValueModel.removePropertyChangeListener(PropertyValueModel.VALUE, this);
+ }
+
+
+ // ********** PropertyChangeListener **********
+
+ public void propertyChanged(PropertyChangeEvent event) {
+ @SuppressWarnings("unchecked")
+ V newWrappedValue = (V) event.getNewValue();
+ this.wrappedValueChanged(newWrappedValue);
+ }
+
+ /**
+ * If we have a <em>buffered</em> value, check whether the <em>wrapped</em> value has
+ * changed to be the same as the <em>buffered</em> value. If it has, stop <em>buffering</em>;
+ * if not, do nothing.
+ * If we do not yet have a <em>buffered</em> value, simply propagate the
+ * change notification with the buffered model as the source.
+ * <p>
+ * <strong>NB:</strong>
+ * By default, if we have a <em>buffered</em> value and the <em>wrapped</em> value changes
+ * to something other than the current <em>buffered</em> value,
+ * we simply ignore the new <em>wrapped</em> value and simply overlay it with the
+ * <em>buffered</em> value if it is <em>accepted</em>. ("Last One In Wins" concurrency model)
+ * Subclasses can override this method to change that behavior with a
+ * different concurrency model. For example, it could drop the <em>buffered</em> value
+ * and replace it with the new <em>wrapped</em> value, or it could throw an
+ * exception.
+ */
+ private void wrappedValueChanged(V newWrappedValue) {
+ this.wrappedValue = newWrappedValue;
+ if (this.isBuffering()) {
+ if (ObjectTools.equals(this.bufferedValue, this.wrappedValue)) {
+ // if the buffered value is now the same as the original value,
+ // there is no need to continue "buffering"
+ this.bufferedValue = null;
+ this.setBuffering(false);
+ } else {
+ // NOP - see note in method comment
+ }
+ } else {
+ this.listener.valueChanged(this.wrappedValue);
+ }
+ }
+
+
+ // ********** Trigger calls **********
+
+ /**
+ * The trigger has been accepted.
+ * If we are buffering, push the {@link #bufferedValue} to the {@link #wrappedValue}.
+ * The resulting change event will clear the {@link #bufferedValue}
+ * and the {@link #bufferingModel buffering} flag.
+ */
+ /* CU private */ void accept() {
+ if (this.isBuffering()) {
+ // the resulting change event will clear the 'bufferedValue' and the 'buffering' flag
+ this.wrappedValueModel.setValue(this.bufferedValue);
+ }
+ }
+
+ /**
+ * The trigger has been reset.
+ * If we are buffering, clear the {@link #bufferedValue}
+ * and the {@link #bufferingModel buffering} flag and notify our listener
+ * that our value has reverted to the original {@link #wrappedValue}.
+ */
+ /* CU private */ void reset() {
+ if (this.isBuffering()) {
+ this.bufferedValue = null;
+ this.setBuffering(false);
+ this.listener.valueChanged(this.wrappedValue);
+ }
+ }
+
+
+ // ********** misc **********
+
+ private boolean isBuffering() {
+ return this.bufferingModel.getValue().booleanValue();
+ }
+
+ private void setBuffering(boolean buffering) {
+ this.bufferingModel.setValue(Boolean.valueOf(buffering));
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ if (this.isBuffering()) {
+ sb.append(this.bufferedValue);
+ sb.append(" ["); //$NON-NLS-1$
+ sb.append(this.wrappedValue);
+ sb.append("]"); //$NON-NLS-1$
+ } else {
+ sb.append(this.wrappedValue);
+ }
+ return ObjectTools.toString(this, sb.toString());
+ }
+
+
+ // ********** Trigger **********
+
+ /**
+ * A trigger is used to <em>accept</em> or <em>reset</em> one or more
+ * buffered value models.
+ */
+ public static class Trigger {
+ private final ListenerList<Listener> listenerList = ModelTools.listenerList();
+
+ public Trigger() {
+ super();
+ }
+
+ /**
+ * Accept the trigger.
+ */
+ public void accept() {
+ for (Listener listener : this.listenerList) {
+ listener.accept();
+ }
+ }
+
+ /**
+ * Reset the trigger.
+ */
+ public void reset() {
+ for (Listener listener : this.listenerList) {
+ listener.reset();
+ }
+ }
+
+ public void addListener(Listener listener) {
+ this.listenerList.add(listener);
+ }
+
+ public void removeListener(Listener listener) {
+ this.listenerList.remove(listener);
+ }
+
+ @Override
+ public String toString() {
+ return ObjectTools.toString(this);
+ }
+
+ public interface Listener {
+ void reset();
+ void accept();
+ }
+ }
+
+
+ // ********** Factory **********
+
+ public static class Factory<V>
+ implements PluggableModifiablePropertyValueModel.Adapter.Factory<V>
+ {
+ /* CU private */ final ModifiablePropertyValueModel<V> wrappedValueModel;
+ /* CU private */ final Trigger trigger;
+ /* CU private */ final SimplePropertyValueModel<Boolean> bufferingModel = new SimplePropertyValueModel<>(Boolean.FALSE);
+
+ public Factory(ModifiablePropertyValueModel<V> wrappedValueModel, Trigger trigger) {
+ super();
+ if (wrappedValueModel == null) {
+ throw new NullPointerException();
+ }
+ this.wrappedValueModel = wrappedValueModel;
+ if (trigger == null) {
+ throw new NullPointerException();
+ }
+ this.trigger = trigger;
+ }
+
+ public PropertyValueModel<Boolean> getBufferingModel() {
+ return this.bufferingModel;
+ }
+
+ public BufferedPropertyValueModelAdapter<V> buildAdapter(BasePluggablePropertyValueModel.Adapter.Listener<V> listener) {
+ return new BufferedPropertyValueModelAdapter<>(this, listener);
+ }
+
+ @Override
+ public String toString() {
+ return ObjectTools.toString(this);
+ }
+ }
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/PropertyValueModelTools.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/PropertyValueModelTools.java
index 3932494f74..7907f101fa 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/PropertyValueModelTools.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/PropertyValueModelTools.java
@@ -10,7 +10,9 @@
package org.eclipse.jpt.common.utility.internal.model.value;
import java.util.Collection;
+import org.eclipse.jpt.common.utility.Association;
import org.eclipse.jpt.common.utility.closure.Closure;
+import org.eclipse.jpt.common.utility.internal.SimpleAssociation;
import org.eclipse.jpt.common.utility.internal.predicate.PredicateTools;
import org.eclipse.jpt.common.utility.internal.transformer.TransformerAdapter;
import org.eclipse.jpt.common.utility.internal.transformer.TransformerTools;
@@ -500,6 +502,34 @@ public final class PropertyValueModelTools {
}
+ // ********** buffered wrapper **********
+
+ /**
+ * Construct a trigger that can be used to accept or reset one or more
+ * buffered property value models (or any other listeners).
+ *
+ * @see #buffer(ModifiablePropertyValueModel, BufferedPropertyValueModelAdapter.Trigger)
+ */
+ public static BufferedPropertyValueModelAdapter.Trigger bufferedPropertyValueModelAdapterTrigger() {
+ return new BufferedPropertyValueModelAdapter.Trigger();
+ }
+
+ /**
+ * Construct a property value model that wraps the specified
+ * property value model and buffers its value, using the specified trigger.
+ *
+ * @see BufferedPropertyValueModelAdapter
+ * @see #bufferedPropertyValueModelAdapterTrigger()
+ * @see PluggablePropertyValueModel
+ */
+ public static <V> Association<ModifiablePropertyValueModel<V>, PropertyValueModel<Boolean>> buffer(ModifiablePropertyValueModel<V> propertyModel, BufferedPropertyValueModelAdapter.Trigger trigger) {
+ BufferedPropertyValueModelAdapter.Factory<V> factory = new BufferedPropertyValueModelAdapter.Factory<>(propertyModel, trigger);
+ ModifiablePropertyValueModel<V> model = modifiablePropertyValueModel(factory);
+ PropertyValueModel<Boolean> bufferingModel = factory.getBufferingModel();
+ return new SimpleAssociation<>(model, bufferingModel);
+ }
+
+
// ********** null check wrapper **********
/**
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/PropertyValueModelWrapper.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/PropertyValueModelWrapper.java
deleted file mode 100644
index 8cb4841bb7..0000000000
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/PropertyValueModelWrapper.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2016 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.common.utility.internal.model.value;
-
-import org.eclipse.jpt.common.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.common.utility.model.listener.PropertyChangeAdapter;
-import org.eclipse.jpt.common.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
-
-/**
- * This abstract class provides the infrastructure needed to wrap
- * another property value model, "lazily" listen to it, and propagate
- * its change notifications. Subclasses must implement the appropriate
- * {@link PropertyValueModel}.
- * <p>
- * Subclasses must implement at least one of the following methods:<ul>
- * <li>{@link #wrappedValueChanged(PropertyChangeEvent)}<p>
- * implement this method to propagate the appropriate change notification
- * <li>{@link #wrappedValueChanged(Object, Object) wrappedValueChanged(V, V)}<p>
- * implement this method to propagate the appropriate change notification
- * <li>{@link #wrappedValueChanged(Object) wrappedValueChanged(V)}<p>
- * implement this method to propagate the appropriate change notification
- * </ul>
- *
- * @param <V> the type of the <em>wrapped</em> model's value
- */
-public abstract class PropertyValueModelWrapper<V>
- extends AbstractPropertyValueModel
-{
- /** The wrapped property value model. Never <code>null</code>. */
- protected final PropertyValueModel<? extends V> valueModel;
-
- /** A listener that allows us to sync with changes to the wrapped value model. */
- protected final PropertyChangeListener valueListener;
-
-
- // ********** constructors/initialization **********
-
- /**
- * Construct a property value model with the specified wrapped
- * property value model.
- */
- protected PropertyValueModelWrapper(PropertyValueModel<? extends V> valueModel) {
- super();
- if (valueModel == null) {
- throw new NullPointerException();
- }
- this.valueModel = valueModel;
- this.valueListener = this.buildValueListener();
- }
-
- protected PropertyChangeListener buildValueListener() {
- return new ValueListener();
- }
-
- /* CU private */ class ValueListener
- extends PropertyChangeAdapter
- {
- @Override
- public void propertyChanged(PropertyChangeEvent event) {
- PropertyValueModelWrapper.this.wrappedValueChanged(event);
- }
- }
-
-
- // ********** listen to wrapped value model **********
-
- /**
- * Begin listening to the value model.
- */
- @Override
- protected void engageModel() {
- this.valueModel.addPropertyChangeListener(PropertyValueModel.VALUE, this.valueListener);
- }
-
- /**
- * Stop listening to the value model.
- */
- @Override
- protected void disengageModel() {
- this.valueModel.removePropertyChangeListener(PropertyValueModel.VALUE, this.valueListener);
- }
-
-
- // ********** property change support **********
-
- /**
- * The value of the wrapped value model has changed;
- * propagate the change notification appropriately.
- * @see #wrappedValueChanged(Object, Object)
- * @see #wrappedValueChanged(Object)
- */
- @SuppressWarnings("unchecked")
- protected void wrappedValueChanged(PropertyChangeEvent event) {
- this.wrappedValueChanged((V) event.getOldValue(), (V) event.getNewValue());
- }
-
- /**
- * The value of the wrapped value model has changed;
- * propagate the change notification appropriately.
- * @see #wrappedValueChanged(PropertyChangeEvent)
- * @see #wrappedValueChanged(Object)
- */
- protected void wrappedValueChanged(@SuppressWarnings("unused") V oldValue, V newValue) {
- this.wrappedValueChanged(newValue);
- }
-
- /**
- * The value of the wrapped value model has changed;
- * propagate the change notification appropriately.
- * @see #wrappedValueChanged(PropertyChangeEvent)
- * @see #wrappedValueChanged(Object, Object)
- */
- protected void wrappedValueChanged(@SuppressWarnings("unused") V newValue) {
- throw new RuntimeException("This method was not overridden."); //$NON-NLS-1$
- }
-}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/BufferedModifiablePropertyValueModelTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/BufferedModifiablePropertyValueModelTests.java
deleted file mode 100644
index fa7ed7c89e..0000000000
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/BufferedModifiablePropertyValueModelTests.java
+++ /dev/null
@@ -1,504 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2012 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.common.utility.tests.internal.model.value;
-
-import java.util.Date;
-import junit.framework.TestCase;
-import org.eclipse.jpt.common.utility.internal.model.AbstractModel;
-import org.eclipse.jpt.common.utility.internal.model.value.BufferedModifiablePropertyValueModel;
-import org.eclipse.jpt.common.utility.internal.model.value.PropertyAspectAdapter;
-import org.eclipse.jpt.common.utility.internal.model.value.SimplePropertyValueModel;
-import org.eclipse.jpt.common.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.common.utility.model.listener.ChangeAdapter;
-import org.eclipse.jpt.common.utility.model.listener.ChangeListener;
-import org.eclipse.jpt.common.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.common.utility.model.value.ModifiablePropertyValueModel;
-import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
-import org.eclipse.jpt.common.utility.tests.internal.TestTools;
-
-@SuppressWarnings("nls")
-public class BufferedModifiablePropertyValueModelTests
- extends TestCase
-{
- private Employee employee;
- private ModifiablePropertyValueModel<Employee> employeeHolder;
- PropertyChangeEvent employeeEvent;
-
- private ModifiablePropertyValueModel<Integer> idAdapter;
- private ModifiablePropertyValueModel<String> nameAdapter;
- private ModifiablePropertyValueModel<Date> hireDateAdapter;
- PropertyChangeEvent adapterEvent;
-
- private BufferedModifiablePropertyValueModel.Trigger trigger;
- private BufferedModifiablePropertyValueModel<Integer> bufferedIDHolder;
- private BufferedModifiablePropertyValueModel<String> bufferedNameHolder;
- private BufferedModifiablePropertyValueModel<Date> bufferedHireDateHolder;
- PropertyChangeEvent bufferedEvent;
-
- public BufferedModifiablePropertyValueModelTests(String name) {
- super(name);
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- this.employee = new Employee(17, "Freddy", new Date());
- this.employeeHolder = new SimplePropertyValueModel<Employee>(this.employee);
-
- this.trigger = new BufferedModifiablePropertyValueModel.Trigger();
-
- this.idAdapter = this.buildIDAdapter(this.employeeHolder);
- this.bufferedIDHolder = new BufferedModifiablePropertyValueModel<Integer>(this.idAdapter, this.trigger);
-
- this.nameAdapter = this.buildNameAdapter(this.employeeHolder);
- this.bufferedNameHolder = new BufferedModifiablePropertyValueModel<String>(this.nameAdapter, this.trigger);
-
- this.hireDateAdapter = this.buildHireDateAdapter(this.employeeHolder);
- this.bufferedHireDateHolder = new BufferedModifiablePropertyValueModel<Date>(this.hireDateAdapter, this.trigger);
- }
-
- private ModifiablePropertyValueModel<Integer> buildIDAdapter(PropertyValueModel<Employee> eHolder) {
- return new PropertyAspectAdapter<Employee, Integer>(eHolder, Employee.ID_PROPERTY) {
- @Override
- protected Integer buildValue_() {
- return new Integer(this.subject.getID());
- }
- @Override
- protected void setValue_(Integer value) {
- this.subject.setID(value.intValue());
- }
- };
- }
-
- private ModifiablePropertyValueModel<String> buildNameAdapter(PropertyValueModel<Employee> eHolder) {
- return new PropertyAspectAdapter<Employee, String>(eHolder, Employee.NAME_PROPERTY) {
- @Override
- protected String buildValue_() {
- return this.subject.getName();
- }
- @Override
- protected void setValue_(String value) {
- this.subject.setName(value);
- }
- };
- }
-
- private ModifiablePropertyValueModel<Date> buildHireDateAdapter(PropertyValueModel<Employee> eHolder) {
- return new PropertyAspectAdapter<Employee, Date>(eHolder, Employee.HIRE_DATE_PROPERTY) {
- @Override
- protected Date buildValue_() {
- return this.subject.getHireDate();
- }
- @Override
- protected void setValue_(Date value) {
- this.subject.setHireDate(value);
- }
- };
- }
-
- @Override
- protected void tearDown() throws Exception {
- TestTools.clear(this);
- super.tearDown();
- }
-
- public void testGetValue() {
- PropertyChangeListener bufferedListener = this.buildBufferedListener();
- this.bufferedIDHolder.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
- this.bufferedNameHolder.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
- this.bufferedHireDateHolder.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
-
- assertEquals(new Integer(17), this.idAdapter.getValue());
- assertEquals(new Integer(17), this.bufferedIDHolder.getValue());
-
- assertEquals("Freddy", this.employee.getName());
- assertEquals("Freddy", this.nameAdapter.getValue());
- assertEquals("Freddy", this.bufferedNameHolder.getValue());
-
- Date temp = this.employee.getHireDate();
- assertEquals(temp, this.employee.getHireDate());
- assertEquals(temp, this.hireDateAdapter.getValue());
- assertEquals(temp, this.bufferedHireDateHolder.getValue());
-
- this.bufferedIDHolder.setValue(new Integer(323));
- assertEquals(17, this.employee.getID());
- assertEquals(new Integer(17), this.idAdapter.getValue());
- assertEquals(new Integer(323), this.bufferedIDHolder.getValue());
-
- this.bufferedNameHolder.setValue("Ripley");
- assertEquals("Freddy", this.employee.getName());
- assertEquals("Freddy", this.nameAdapter.getValue());
- assertEquals("Ripley", this.bufferedNameHolder.getValue());
-
- this.bufferedHireDateHolder.setValue(null);
- assertEquals(temp, this.employee.getHireDate());
- assertEquals(temp, this.hireDateAdapter.getValue());
- assertEquals(null, this.bufferedHireDateHolder.getValue());
- }
-
- public void testTriggerAccept() {
- PropertyChangeListener bufferedListener = this.buildBufferedListener();
- this.bufferedIDHolder.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
- this.bufferedNameHolder.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
- this.bufferedHireDateHolder.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
-
- this.bufferedIDHolder.setValue(new Integer(323));
- assertEquals(17, this.employee.getID());
- assertEquals(new Integer(17), this.idAdapter.getValue());
- assertEquals(new Integer(323), this.bufferedIDHolder.getValue());
-
- this.bufferedNameHolder.setValue("Ripley");
- assertEquals("Freddy", this.employee.getName());
- assertEquals("Freddy", this.nameAdapter.getValue());
- assertEquals("Ripley", this.bufferedNameHolder.getValue());
-
- Date temp = this.employee.getHireDate();
- this.bufferedHireDateHolder.setValue(null);
- assertEquals(temp, this.employee.getHireDate());
- assertEquals(temp, this.hireDateAdapter.getValue());
- assertEquals(null, this.bufferedHireDateHolder.getValue());
-
- this.trigger.accept();
-
- assertEquals(323, this.employee.getID());
- assertEquals(new Integer(323), this.idAdapter.getValue());
- assertEquals(new Integer(323), this.bufferedIDHolder.getValue());
-
- assertEquals("Ripley", this.employee.getName());
- assertEquals("Ripley", this.nameAdapter.getValue());
- assertEquals("Ripley", this.bufferedNameHolder.getValue());
-
- assertEquals(null, this.employee.getHireDate());
- assertEquals(null, this.hireDateAdapter.getValue());
- assertEquals(null, this.bufferedHireDateHolder.getValue());
- }
-
- public void testTriggerReset() {
- PropertyChangeListener bufferedListener = this.buildBufferedListener();
- this.bufferedIDHolder.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
- this.bufferedNameHolder.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
- this.bufferedHireDateHolder.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
-
- this.bufferedIDHolder.setValue(new Integer(323));
- assertEquals(17, this.employee.getID());
- assertEquals(new Integer(17), this.idAdapter.getValue());
- assertEquals(new Integer(323), this.bufferedIDHolder.getValue());
-
- this.bufferedNameHolder.setValue("Ripley");
- assertEquals("Freddy", this.employee.getName());
- assertEquals("Freddy", this.nameAdapter.getValue());
- assertEquals("Ripley", this.bufferedNameHolder.getValue());
-
- Date temp = this.employee.getHireDate();
- this.bufferedHireDateHolder.setValue(null);
- assertEquals(temp, this.employee.getHireDate());
- assertEquals(temp, this.hireDateAdapter.getValue());
- assertEquals(null, this.bufferedHireDateHolder.getValue());
-
- this.trigger.reset();
-
- assertEquals(17, this.employee.getID());
- assertEquals(new Integer(17), this.idAdapter.getValue());
- assertEquals(new Integer(17), this.bufferedIDHolder.getValue());
-
- assertEquals("Freddy", this.employee.getName());
- assertEquals("Freddy", this.nameAdapter.getValue());
- assertEquals("Freddy", this.bufferedNameHolder.getValue());
-
- assertEquals(temp, this.employee.getHireDate());
- assertEquals(temp, this.hireDateAdapter.getValue());
- assertEquals(temp, this.bufferedHireDateHolder.getValue());
- }
-
- public void testLazyListening() {
- assertTrue(((AbstractModel) this.bufferedIDHolder).hasNoPropertyChangeListeners(PropertyValueModel.VALUE));
- assertTrue(((AbstractModel) this.bufferedNameHolder).hasNoPropertyChangeListeners(PropertyValueModel.VALUE));
- assertTrue(((AbstractModel) this.bufferedHireDateHolder).hasNoPropertyChangeListeners(PropertyValueModel.VALUE));
-
- assertTrue(((AbstractModel) this.idAdapter).hasNoPropertyChangeListeners(PropertyValueModel.VALUE));
- assertTrue(((AbstractModel) this.nameAdapter).hasNoPropertyChangeListeners(PropertyValueModel.VALUE));
- assertTrue(((AbstractModel) this.hireDateAdapter).hasNoPropertyChangeListeners(PropertyValueModel.VALUE));
-
- assertTrue(this.employee.hasNoPropertyChangeListeners(Employee.ID_PROPERTY));
- assertTrue(this.employee.hasNoPropertyChangeListeners(Employee.NAME_PROPERTY));
- assertTrue(this.employee.hasNoPropertyChangeListeners(Employee.HIRE_DATE_PROPERTY));
-
- PropertyChangeListener bufferedListener = this.buildBufferedListener();
- this.bufferedIDHolder.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
- this.bufferedNameHolder.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
- this.bufferedHireDateHolder.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
-
- assertTrue(((AbstractModel) this.bufferedIDHolder).hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
- assertTrue(((AbstractModel) this.bufferedNameHolder).hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
- assertTrue(((AbstractModel) this.bufferedHireDateHolder).hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
-
- assertTrue(((AbstractModel) this.idAdapter).hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
- assertTrue(((AbstractModel) this.nameAdapter).hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
- assertTrue(((AbstractModel) this.hireDateAdapter).hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
-
- assertTrue(this.employee.hasAnyPropertyChangeListeners(Employee.ID_PROPERTY));
- assertTrue(this.employee.hasAnyPropertyChangeListeners(Employee.NAME_PROPERTY));
- assertTrue(this.employee.hasAnyPropertyChangeListeners(Employee.HIRE_DATE_PROPERTY));
-
- this.bufferedIDHolder.removePropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
- this.bufferedNameHolder.removePropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
- this.bufferedHireDateHolder.removePropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
-
- assertTrue(((AbstractModel) this.bufferedIDHolder).hasNoPropertyChangeListeners(PropertyValueModel.VALUE));
- assertTrue(((AbstractModel) this.bufferedNameHolder).hasNoPropertyChangeListeners(PropertyValueModel.VALUE));
- assertTrue(((AbstractModel) this.bufferedHireDateHolder).hasNoPropertyChangeListeners(PropertyValueModel.VALUE));
-
- assertTrue(((AbstractModel) this.idAdapter).hasNoPropertyChangeListeners(PropertyValueModel.VALUE));
- assertTrue(((AbstractModel) this.nameAdapter).hasNoPropertyChangeListeners(PropertyValueModel.VALUE));
- assertTrue(((AbstractModel) this.hireDateAdapter).hasNoPropertyChangeListeners(PropertyValueModel.VALUE));
-
- assertTrue(this.employee.hasNoPropertyChangeListeners(Employee.ID_PROPERTY));
- assertTrue(this.employee.hasNoPropertyChangeListeners(Employee.NAME_PROPERTY));
- assertTrue(this.employee.hasNoPropertyChangeListeners(Employee.HIRE_DATE_PROPERTY));
- }
-
- public void testPropertyChange1() {
- PropertyChangeListener bufferedListener = this.buildBufferedListener();
- this.bufferedNameHolder.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
-
- PropertyChangeListener adapterListener = this.buildAdapterListener();
- this.nameAdapter.addPropertyChangeListener(PropertyValueModel.VALUE, adapterListener);
-
- PropertyChangeListener employeeListener = this.buildEmployeeListener();
- this.employee.addPropertyChangeListener(Employee.NAME_PROPERTY, employeeListener);
-
- this.verifyPropertyChanges();
- }
-
- public void testPropertyChange2() {
- ChangeListener bufferedListener = this.buildBufferedListener();
- this.bufferedNameHolder.addChangeListener(bufferedListener);
-
- ChangeListener adapterListener = this.buildAdapterListener();
- this.nameAdapter.addChangeListener(adapterListener);
-
- ChangeListener employeeListener = this.buildEmployeeListener();
- this.employee.addChangeListener(employeeListener);
-
- this.verifyPropertyChanges();
- }
-
- private void verifyPropertyChanges() {
- this.bufferedEvent = null;
- this.adapterEvent = null;
- this.employeeEvent = null;
- this.bufferedNameHolder.setValue("Ripley");
- this.verifyEvent(this.bufferedEvent, this.bufferedNameHolder, PropertyValueModel.VALUE, "Freddy", "Ripley");
- assertNull(this.adapterEvent);
- assertNull(this.employeeEvent);
-
- this.bufferedEvent = null;
- this.adapterEvent = null;
- this.employeeEvent = null;
- this.bufferedNameHolder.setValue("Charlie");
- this.verifyEvent(this.bufferedEvent, this.bufferedNameHolder, PropertyValueModel.VALUE, "Ripley", "Charlie");
- assertNull(this.adapterEvent);
- assertNull(this.employeeEvent);
-
- this.bufferedEvent = null;
- this.adapterEvent = null;
- this.employeeEvent = null;
- this.trigger.accept();
- assertNull(this.bufferedEvent);
- this.verifyEvent(this.adapterEvent, this.nameAdapter, PropertyValueModel.VALUE, "Freddy", "Charlie");
- this.verifyEvent(this.employeeEvent, this.employee, Employee.NAME_PROPERTY, "Freddy", "Charlie");
-
- this.bufferedEvent = null;
- this.adapterEvent = null;
- this.employeeEvent = null;
- this.bufferedNameHolder.setValue("Jason");
- this.verifyEvent(this.bufferedEvent, this.bufferedNameHolder, PropertyValueModel.VALUE, "Charlie", "Jason");
- assertNull(this.adapterEvent);
- assertNull(this.employeeEvent);
-
- this.bufferedEvent = null;
- this.adapterEvent = null;
- this.employeeEvent = null;
- this.trigger.reset();
- this.verifyEvent(this.bufferedEvent, this.bufferedNameHolder, PropertyValueModel.VALUE, "Jason", "Charlie");
- assertNull(this.adapterEvent);
- assertNull(this.employeeEvent);
- }
-
- /**
- * changing the value should trigger buffering
- */
- public void testBuffering1() {
- PropertyChangeListener bufferedListener = this.buildBufferedListener();
- this.bufferedNameHolder.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
-
- this.bufferedNameHolder.setValue("Ripley");
- assertEquals("Freddy", this.nameAdapter.getValue());
- assertEquals("Ripley", this.bufferedNameHolder.getValue());
- assertTrue(this.bufferedNameHolder.isBuffering());
- }
-
- /**
- * setting to the same value should not trigger buffering (?)
- */
- public void testBuffering2() {
- PropertyChangeListener bufferedListener = this.buildBufferedListener();
- this.bufferedNameHolder.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
-
- this.bufferedNameHolder.setValue("Freddy");
- assertEquals("Freddy", this.bufferedNameHolder.getValue());
- assertEquals("Freddy", this.nameAdapter.getValue());
- assertFalse(this.bufferedNameHolder.isBuffering());
- }
-
- /**
- * setting to the original value should not trigger buffering (?)
- */
- public void testBuffering3() {
- PropertyChangeListener bufferedListener = this.buildBufferedListener();
- this.bufferedNameHolder.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
-
- this.bufferedNameHolder.setValue("Ripley");
- assertEquals("Freddy", this.nameAdapter.getValue());
- assertEquals("Ripley", this.bufferedNameHolder.getValue());
- assertTrue(this.bufferedNameHolder.isBuffering());
-
- this.bufferedNameHolder.setValue("Freddy");
- assertEquals("Freddy", this.nameAdapter.getValue());
- assertEquals("Freddy", this.bufferedNameHolder.getValue());
- assertFalse(this.bufferedNameHolder.isBuffering());
- }
-
- /**
- * back-door changes are ignored - "Last One In Wins"
- */
- public void testChangeConflict1() {
- PropertyChangeListener bufferedListener = this.buildBufferedListener();
- this.bufferedNameHolder.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
-
- this.bufferedNameHolder.setValue("Ripley");
- assertEquals("Freddy", this.employee.getName());
- assertEquals("Freddy", this.nameAdapter.getValue());
- assertEquals("Ripley", this.bufferedNameHolder.getValue());
-
- this.nameAdapter.setValue("Jason");
- assertEquals("Jason", this.employee.getName());
- assertEquals("Jason", this.nameAdapter.getValue());
- assertEquals("Ripley", this.bufferedNameHolder.getValue());
-
- this.trigger.accept();
- // "Jason" is dropped on the floor...
- assertEquals("Ripley", this.employee.getName());
- assertEquals("Ripley", this.nameAdapter.getValue());
- assertEquals("Ripley", this.bufferedNameHolder.getValue());
- }
-
- /**
- * back-door changes can de-activate buffering (?)
- */
- public void testChangeConflict2() {
- PropertyChangeListener bufferedListener = this.buildBufferedListener();
- this.bufferedNameHolder.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
-
- this.bufferedNameHolder.setValue("Ripley");
- assertEquals("Freddy", this.employee.getName());
- assertEquals("Freddy", this.nameAdapter.getValue());
- assertEquals("Ripley", this.bufferedNameHolder.getValue());
- assertTrue(this.bufferedNameHolder.isBuffering());
-
- this.nameAdapter.setValue("Ripley");
- assertEquals("Ripley", this.employee.getName());
- assertEquals("Ripley", this.nameAdapter.getValue());
- assertEquals("Ripley", this.bufferedNameHolder.getValue());
- assertFalse(this.bufferedNameHolder.isBuffering());
- }
-
- private ChangeListener buildBufferedListener() {
- return new ChangeAdapter() {
- @Override
- public void propertyChanged(PropertyChangeEvent e) {
- BufferedModifiablePropertyValueModelTests.this.bufferedEvent = e;
- }
- };
- }
-
- private ChangeListener buildAdapterListener() {
- return new ChangeAdapter() {
- @Override
- public void propertyChanged(PropertyChangeEvent e) {
- BufferedModifiablePropertyValueModelTests.this.adapterEvent = e;
- }
- };
- }
-
- private ChangeListener buildEmployeeListener() {
- return new ChangeAdapter() {
- @Override
- public void propertyChanged(PropertyChangeEvent e) {
- BufferedModifiablePropertyValueModelTests.this.employeeEvent = e;
- }
- };
- }
-
- private void verifyEvent(PropertyChangeEvent event, Object source, String propertyName, Object oldValue, Object newValue) {
- assertEquals(source, event.getSource());
- assertEquals(propertyName, event.getPropertyName());
- assertEquals(oldValue, event.getOldValue());
- assertEquals(newValue, event.getNewValue());
- }
-
-
- // ********** inner class **********
-
- class Employee extends AbstractModel {
- private int id;
- public static final String ID_PROPERTY = "id";
- private String name;
- public static final String NAME_PROPERTY = "name";
- private Date hireDate;
- public static final String HIRE_DATE_PROPERTY = "hireDate";
-
- Employee(int id, String name, Date hireDate) {
- super();
- this.id = id;
- this.name = name;
- this.hireDate = hireDate;
- }
- int getID() {
- return this.id;
- }
- void setID(int id) {
- int old = this.id;
- this.id = id;
- this.firePropertyChanged(ID_PROPERTY, old, id);
- }
- String getName() {
- return this.name;
- }
- void setName(String name) {
- Object old = this.name;
- this.name = name;
- this.firePropertyChanged(NAME_PROPERTY, old, name);
- }
- Date getHireDate() {
- return this.hireDate;
- }
- void setHireDate(Date hireDate) {
- Object old = this.hireDate;
- this.hireDate = hireDate;
- this.firePropertyChanged(HIRE_DATE_PROPERTY, old, hireDate);
- }
- @Override
- public void toString(StringBuilder sb) {
- sb.append(this.name);
- }
- }
-}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/BufferedPropertyValueModelTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/BufferedPropertyValueModelTests.java
new file mode 100644
index 0000000000..bf831c5293
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/BufferedPropertyValueModelTests.java
@@ -0,0 +1,597 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2016 Oracle. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0, which accompanies this distribution
+ * and is available at http://www.eclipse.org/legal/epl-v10.html.
+ *
+ * Contributors:
+ * Oracle - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.jpt.common.utility.tests.internal.model.value;
+
+import java.util.Date;
+import org.eclipse.jpt.common.utility.Association;
+import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.internal.model.AbstractModel;
+import org.eclipse.jpt.common.utility.internal.model.value.BufferedPropertyValueModelAdapter;
+import org.eclipse.jpt.common.utility.internal.model.value.PropertyAspectAdapter;
+import org.eclipse.jpt.common.utility.internal.model.value.PropertyValueModelTools;
+import org.eclipse.jpt.common.utility.internal.model.value.SimplePropertyValueModel;
+import org.eclipse.jpt.common.utility.model.event.PropertyChangeEvent;
+import org.eclipse.jpt.common.utility.model.listener.ChangeAdapter;
+import org.eclipse.jpt.common.utility.model.listener.ChangeListener;
+import org.eclipse.jpt.common.utility.model.listener.PropertyChangeListener;
+import org.eclipse.jpt.common.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
+import org.eclipse.jpt.common.utility.tests.internal.TestTools;
+import junit.framework.TestCase;
+
+@SuppressWarnings("nls")
+public class BufferedPropertyValueModelTests
+ extends TestCase
+{
+ private Employee employee;
+ private ModifiablePropertyValueModel<Employee> employeeModel;
+ PropertyChangeEvent employeeEvent;
+
+ private ModifiablePropertyValueModel<Integer> idModel;
+ private ModifiablePropertyValueModel<String> nameModel;
+ private ModifiablePropertyValueModel<Date> hireDateModel;
+ PropertyChangeEvent adapterEvent;
+
+ private BufferedPropertyValueModelAdapter.Trigger trigger;
+
+ private ModifiablePropertyValueModel<Integer> bufferedIDModel;
+
+ private ModifiablePropertyValueModel<String> bufferedNameModel;
+ private PropertyValueModel<Boolean> nameIsBufferingModel;
+
+ private ModifiablePropertyValueModel<Date> bufferedHireDateModel;
+
+ PropertyChangeEvent bufferedEvent;
+
+ public BufferedPropertyValueModelTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ this.employee = new Employee(17, "Freddy", new Date());
+ this.employeeModel = new SimplePropertyValueModel<>(this.employee);
+
+ this.trigger = PropertyValueModelTools.bufferedPropertyValueModelAdapterTrigger();
+
+ this.idModel = this.buildIDModel(this.employeeModel);
+ Association<ModifiablePropertyValueModel<Integer>, PropertyValueModel<Boolean>> idAssociation = PropertyValueModelTools.buffer(this.idModel, this.trigger);
+ this.bufferedIDModel = idAssociation.getKey();
+
+ this.nameModel = this.buildNameModel(this.employeeModel);
+ Association<ModifiablePropertyValueModel<String>, PropertyValueModel<Boolean>> nameAssociation = PropertyValueModelTools.buffer(this.nameModel, this.trigger);
+ this.bufferedNameModel = nameAssociation.getKey();
+ this.nameIsBufferingModel = nameAssociation.getValue();
+
+ this.hireDateModel = this.buildHireDateModel(this.employeeModel);
+ Association<ModifiablePropertyValueModel<Date>, PropertyValueModel<Boolean>> hireDateAssociation = PropertyValueModelTools.buffer(this.hireDateModel, this.trigger);
+ this.bufferedHireDateModel = hireDateAssociation.getKey();
+ }
+
+ private ModifiablePropertyValueModel<Integer> buildIDModel(PropertyValueModel<Employee> eHolder) {
+ return new PropertyAspectAdapter<Employee, Integer>(eHolder, Employee.ID_PROPERTY) {
+ @Override
+ protected Integer buildValue_() {
+ return new Integer(this.subject.getID());
+ }
+ @Override
+ protected void setValue_(Integer value) {
+ this.subject.setID(value.intValue());
+ }
+ };
+ }
+
+ private ModifiablePropertyValueModel<String> buildNameModel(PropertyValueModel<Employee> eHolder) {
+ return new PropertyAspectAdapter<Employee, String>(eHolder, Employee.NAME_PROPERTY) {
+ @Override
+ protected String buildValue_() {
+ return this.subject.getName();
+ }
+ @Override
+ protected void setValue_(String value) {
+ this.subject.setName(value);
+ }
+ };
+ }
+
+ private ModifiablePropertyValueModel<Date> buildHireDateModel(PropertyValueModel<Employee> eHolder) {
+ return new PropertyAspectAdapter<Employee, Date>(eHolder, Employee.HIRE_DATE_PROPERTY) {
+ @Override
+ protected Date buildValue_() {
+ return this.subject.getHireDate();
+ }
+ @Override
+ protected void setValue_(Date value) {
+ this.subject.setHireDate(value);
+ }
+ };
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ TestTools.clear(this);
+ super.tearDown();
+ }
+
+ public void testGetValue() {
+ PropertyChangeListener bufferedListener = this.buildBufferedListener();
+ this.bufferedIDModel.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
+ this.bufferedNameModel.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
+ this.bufferedHireDateModel.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
+
+ assertEquals(new Integer(17), this.idModel.getValue());
+ assertEquals(new Integer(17), this.bufferedIDModel.getValue());
+
+ assertEquals("Freddy", this.employee.getName());
+ assertEquals("Freddy", this.nameModel.getValue());
+ assertEquals("Freddy", this.bufferedNameModel.getValue());
+
+ Date temp = this.employee.getHireDate();
+ assertEquals(temp, this.employee.getHireDate());
+ assertEquals(temp, this.hireDateModel.getValue());
+ assertEquals(temp, this.bufferedHireDateModel.getValue());
+
+ this.bufferedIDModel.setValue(new Integer(323));
+ assertEquals(17, this.employee.getID());
+ assertEquals(new Integer(17), this.idModel.getValue());
+ assertEquals(new Integer(323), this.bufferedIDModel.getValue());
+
+ this.bufferedNameModel.setValue("Ripley");
+ assertEquals("Freddy", this.employee.getName());
+ assertEquals("Freddy", this.nameModel.getValue());
+ assertEquals("Ripley", this.bufferedNameModel.getValue());
+
+ this.bufferedHireDateModel.setValue(null);
+ assertEquals(temp, this.employee.getHireDate());
+ assertEquals(temp, this.hireDateModel.getValue());
+ assertEquals(null, this.bufferedHireDateModel.getValue());
+ }
+
+ public void testTriggerAccept() {
+ PropertyChangeListener bufferedListener = this.buildBufferedListener();
+ this.bufferedIDModel.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
+ this.bufferedNameModel.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
+ this.bufferedHireDateModel.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
+
+ assertEquals(17, this.employee.getID());
+ assertEquals(new Integer(17), this.idModel.getValue());
+ assertEquals(new Integer(17), this.bufferedIDModel.getValue());
+
+ this.trigger.accept(); // NOP
+
+ assertEquals(17, this.employee.getID());
+ assertEquals(new Integer(17), this.idModel.getValue());
+ assertEquals(new Integer(17), this.bufferedIDModel.getValue());
+
+ this.bufferedIDModel.setValue(new Integer(323));
+ assertEquals(17, this.employee.getID());
+ assertEquals(new Integer(17), this.idModel.getValue());
+ assertEquals(new Integer(323), this.bufferedIDModel.getValue());
+
+ this.bufferedNameModel.setValue("Ripley");
+ assertEquals("Freddy", this.employee.getName());
+ assertEquals("Freddy", this.nameModel.getValue());
+ assertEquals("Ripley", this.bufferedNameModel.getValue());
+
+ Date temp = this.employee.getHireDate();
+ this.bufferedHireDateModel.setValue(null);
+ assertEquals(temp, this.employee.getHireDate());
+ assertEquals(temp, this.hireDateModel.getValue());
+ assertEquals(null, this.bufferedHireDateModel.getValue());
+
+ this.trigger.accept();
+
+ assertEquals(323, this.employee.getID());
+ assertEquals(new Integer(323), this.idModel.getValue());
+ assertEquals(new Integer(323), this.bufferedIDModel.getValue());
+
+ assertEquals("Ripley", this.employee.getName());
+ assertEquals("Ripley", this.nameModel.getValue());
+ assertEquals("Ripley", this.bufferedNameModel.getValue());
+
+ assertNull(this.employee.getHireDate());
+ assertNull(this.hireDateModel.getValue());
+ assertNull(this.bufferedHireDateModel.getValue());
+ }
+
+ public void testTriggerReset() {
+ PropertyChangeListener bufferedListener = this.buildBufferedListener();
+ this.bufferedIDModel.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
+ this.bufferedNameModel.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
+ this.bufferedHireDateModel.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
+
+ assertEquals(17, this.employee.getID());
+ assertEquals(new Integer(17), this.idModel.getValue());
+ assertEquals(new Integer(17), this.bufferedIDModel.getValue());
+
+ this.trigger.reset(); // NOP
+
+ assertEquals(17, this.employee.getID());
+ assertEquals(new Integer(17), this.idModel.getValue());
+ assertEquals(new Integer(17), this.bufferedIDModel.getValue());
+
+ this.bufferedIDModel.setValue(new Integer(323));
+ assertEquals(17, this.employee.getID());
+ assertEquals(new Integer(17), this.idModel.getValue());
+ assertEquals(new Integer(323), this.bufferedIDModel.getValue());
+
+ this.bufferedNameModel.setValue("Ripley");
+ assertEquals("Freddy", this.employee.getName());
+ assertEquals("Freddy", this.nameModel.getValue());
+ assertEquals("Ripley", this.bufferedNameModel.getValue());
+
+ Date temp = this.employee.getHireDate();
+ this.bufferedHireDateModel.setValue(null);
+ assertEquals(temp, this.employee.getHireDate());
+ assertEquals(temp, this.hireDateModel.getValue());
+ assertEquals(null, this.bufferedHireDateModel.getValue());
+
+ this.trigger.reset();
+
+ assertEquals(17, this.employee.getID());
+ assertEquals(new Integer(17), this.idModel.getValue());
+ assertEquals(new Integer(17), this.bufferedIDModel.getValue());
+
+ assertEquals("Freddy", this.employee.getName());
+ assertEquals("Freddy", this.nameModel.getValue());
+ assertEquals("Freddy", this.bufferedNameModel.getValue());
+
+ assertEquals(temp, this.employee.getHireDate());
+ assertEquals(temp, this.hireDateModel.getValue());
+ assertEquals(temp, this.bufferedHireDateModel.getValue());
+ }
+
+ public void testLazyListening() {
+ assertTrue(((AbstractModel) this.bufferedIDModel).hasNoPropertyChangeListeners(PropertyValueModel.VALUE));
+ assertTrue(((AbstractModel) this.bufferedNameModel).hasNoPropertyChangeListeners(PropertyValueModel.VALUE));
+ assertTrue(((AbstractModel) this.bufferedHireDateModel).hasNoPropertyChangeListeners(PropertyValueModel.VALUE));
+
+ assertTrue(((AbstractModel) this.idModel).hasNoPropertyChangeListeners(PropertyValueModel.VALUE));
+ assertTrue(((AbstractModel) this.nameModel).hasNoPropertyChangeListeners(PropertyValueModel.VALUE));
+ assertTrue(((AbstractModel) this.hireDateModel).hasNoPropertyChangeListeners(PropertyValueModel.VALUE));
+
+ assertTrue(this.employee.hasNoPropertyChangeListeners(Employee.ID_PROPERTY));
+ assertTrue(this.employee.hasNoPropertyChangeListeners(Employee.NAME_PROPERTY));
+ assertTrue(this.employee.hasNoPropertyChangeListeners(Employee.HIRE_DATE_PROPERTY));
+
+ PropertyChangeListener bufferedListener = this.buildBufferedListener();
+ this.bufferedIDModel.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
+ this.bufferedNameModel.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
+ this.bufferedHireDateModel.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
+
+ assertTrue(((AbstractModel) this.bufferedIDModel).hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ assertTrue(((AbstractModel) this.bufferedNameModel).hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ assertTrue(((AbstractModel) this.bufferedHireDateModel).hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+
+ assertTrue(((AbstractModel) this.idModel).hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ assertTrue(((AbstractModel) this.nameModel).hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ assertTrue(((AbstractModel) this.hireDateModel).hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+
+ assertTrue(this.employee.hasAnyPropertyChangeListeners(Employee.ID_PROPERTY));
+ assertTrue(this.employee.hasAnyPropertyChangeListeners(Employee.NAME_PROPERTY));
+ assertTrue(this.employee.hasAnyPropertyChangeListeners(Employee.HIRE_DATE_PROPERTY));
+
+ this.bufferedIDModel.removePropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
+ this.bufferedNameModel.removePropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
+ this.bufferedHireDateModel.removePropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
+
+ assertTrue(((AbstractModel) this.bufferedIDModel).hasNoPropertyChangeListeners(PropertyValueModel.VALUE));
+ assertTrue(((AbstractModel) this.bufferedNameModel).hasNoPropertyChangeListeners(PropertyValueModel.VALUE));
+ assertTrue(((AbstractModel) this.bufferedHireDateModel).hasNoPropertyChangeListeners(PropertyValueModel.VALUE));
+
+ assertTrue(((AbstractModel) this.idModel).hasNoPropertyChangeListeners(PropertyValueModel.VALUE));
+ assertTrue(((AbstractModel) this.nameModel).hasNoPropertyChangeListeners(PropertyValueModel.VALUE));
+ assertTrue(((AbstractModel) this.hireDateModel).hasNoPropertyChangeListeners(PropertyValueModel.VALUE));
+
+ assertTrue(this.employee.hasNoPropertyChangeListeners(Employee.ID_PROPERTY));
+ assertTrue(this.employee.hasNoPropertyChangeListeners(Employee.NAME_PROPERTY));
+ assertTrue(this.employee.hasNoPropertyChangeListeners(Employee.HIRE_DATE_PROPERTY));
+ }
+
+ public void testPropertyChange1() {
+ PropertyChangeListener bufferedListener = this.buildBufferedListener();
+ this.bufferedNameModel.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
+
+ PropertyChangeListener adapterListener = this.buildAdapterListener();
+ this.nameModel.addPropertyChangeListener(PropertyValueModel.VALUE, adapterListener);
+
+ PropertyChangeListener employeeListener = this.buildEmployeeListener();
+ this.employee.addPropertyChangeListener(Employee.NAME_PROPERTY, employeeListener);
+
+ this.verifyPropertyChanges();
+ }
+
+ public void testPropertyChange2() {
+ ChangeListener bufferedListener = this.buildBufferedListener();
+ this.bufferedNameModel.addChangeListener(bufferedListener);
+
+ ChangeListener adapterListener = this.buildAdapterListener();
+ this.nameModel.addChangeListener(adapterListener);
+
+ ChangeListener employeeListener = this.buildEmployeeListener();
+ this.employee.addChangeListener(employeeListener);
+
+ this.verifyPropertyChanges();
+ }
+
+ private void verifyPropertyChanges() {
+ this.bufferedEvent = null;
+ this.adapterEvent = null;
+ this.employeeEvent = null;
+ this.bufferedNameModel.setValue("Ripley");
+ this.verifyEvent(this.bufferedEvent, this.bufferedNameModel, PropertyValueModel.VALUE, "Freddy", "Ripley");
+ assertNull(this.adapterEvent);
+ assertNull(this.employeeEvent);
+
+ this.bufferedEvent = null;
+ this.adapterEvent = null;
+ this.employeeEvent = null;
+ this.bufferedNameModel.setValue("Charlie");
+ this.verifyEvent(this.bufferedEvent, this.bufferedNameModel, PropertyValueModel.VALUE, "Ripley", "Charlie");
+ assertNull(this.adapterEvent);
+ assertNull(this.employeeEvent);
+
+ this.bufferedEvent = null;
+ this.adapterEvent = null;
+ this.employeeEvent = null;
+ this.trigger.accept();
+ assertNull(this.bufferedEvent);
+ this.verifyEvent(this.adapterEvent, this.nameModel, PropertyValueModel.VALUE, "Freddy", "Charlie");
+ this.verifyEvent(this.employeeEvent, this.employee, Employee.NAME_PROPERTY, "Freddy", "Charlie");
+
+ this.bufferedEvent = null;
+ this.adapterEvent = null;
+ this.employeeEvent = null;
+ this.bufferedNameModel.setValue("Jason");
+ this.verifyEvent(this.bufferedEvent, this.bufferedNameModel, PropertyValueModel.VALUE, "Charlie", "Jason");
+ assertNull(this.adapterEvent);
+ assertNull(this.employeeEvent);
+
+ this.bufferedEvent = null;
+ this.adapterEvent = null;
+ this.employeeEvent = null;
+ this.trigger.reset();
+ this.verifyEvent(this.bufferedEvent, this.bufferedNameModel, PropertyValueModel.VALUE, "Jason", "Charlie");
+ assertNull(this.adapterEvent);
+ assertNull(this.employeeEvent);
+ }
+
+ /**
+ * changing the value should trigger buffering
+ */
+ public void testBuffering1() {
+ PropertyChangeListener bufferedListener = this.buildBufferedListener();
+ this.bufferedNameModel.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
+
+ this.bufferedNameModel.setValue("Ripley");
+ assertEquals("Freddy", this.nameModel.getValue());
+ assertEquals("Ripley", this.bufferedNameModel.getValue());
+ assertTrue(this.nameIsBufferingModel.getValue().booleanValue());
+ }
+
+ /**
+ * setting to the same value should not trigger buffering (?)
+ */
+ public void testBuffering2() {
+ PropertyChangeListener bufferedListener = this.buildBufferedListener();
+ this.bufferedNameModel.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
+
+ this.bufferedNameModel.setValue("Freddy");
+ assertEquals("Freddy", this.bufferedNameModel.getValue());
+ assertEquals("Freddy", this.nameModel.getValue());
+ assertFalse(this.nameIsBufferingModel.getValue().booleanValue());
+ }
+
+ /**
+ * setting to the original value should not trigger buffering (?)
+ */
+ public void testBuffering3() {
+ PropertyChangeListener bufferedListener = this.buildBufferedListener();
+ this.bufferedNameModel.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
+
+ this.bufferedNameModel.setValue("Ripley");
+ assertEquals("Freddy", this.nameModel.getValue());
+ assertEquals("Ripley", this.bufferedNameModel.getValue());
+ assertTrue(this.nameIsBufferingModel.getValue().booleanValue());
+
+ this.bufferedNameModel.setValue("Freddy");
+ assertEquals("Freddy", this.nameModel.getValue());
+ assertEquals("Freddy", this.bufferedNameModel.getValue());
+ assertFalse(this.nameIsBufferingModel.getValue().booleanValue());
+ }
+
+ /**
+ * back-door changes are ignored - "Last One In Wins"
+ */
+ public void testChangeConflict1() {
+ PropertyChangeListener bufferedListener = this.buildBufferedListener();
+ this.bufferedNameModel.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
+
+ this.bufferedNameModel.setValue("Ripley");
+ assertEquals("Freddy", this.employee.getName());
+ assertEquals("Freddy", this.nameModel.getValue());
+ assertEquals("Ripley", this.bufferedNameModel.getValue());
+
+ this.nameModel.setValue("Jason");
+ assertEquals("Jason", this.employee.getName());
+ assertEquals("Jason", this.nameModel.getValue());
+ assertEquals("Ripley", this.bufferedNameModel.getValue());
+
+ this.trigger.accept();
+ // "Jason" is dropped on the floor...
+ assertEquals("Ripley", this.employee.getName());
+ assertEquals("Ripley", this.nameModel.getValue());
+ assertEquals("Ripley", this.bufferedNameModel.getValue());
+ }
+
+ /**
+ * back-door changes can de-activate buffering (?)
+ */
+ public void testChangeConflict2() {
+ PropertyChangeListener bufferedListener = this.buildBufferedListener();
+ this.bufferedNameModel.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
+
+ this.bufferedNameModel.setValue("Ripley");
+ assertEquals("Freddy", this.employee.getName());
+ assertEquals("Freddy", this.nameModel.getValue());
+ assertEquals("Ripley", this.bufferedNameModel.getValue());
+ assertTrue(this.nameIsBufferingModel.getValue().booleanValue());
+
+ this.nameModel.setValue("Ripley");
+ assertEquals("Ripley", this.employee.getName());
+ assertEquals("Ripley", this.nameModel.getValue());
+ assertEquals("Ripley", this.bufferedNameModel.getValue());
+ assertFalse(this.nameIsBufferingModel.getValue().booleanValue());
+ }
+
+ /**
+ * back-door change when not buffering
+ */
+ public void testChangeConflict3() {
+ PropertyChangeListener bufferedListener = this.buildBufferedListener();
+ this.bufferedNameModel.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
+
+ this.nameModel.setValue("Ripley");
+ assertEquals("Ripley", this.employee.getName());
+ assertEquals("Ripley", this.nameModel.getValue());
+ assertEquals("Ripley", this.bufferedNameModel.getValue());
+ assertEquals("Ripley", this.bufferedEvent.getNewValue());
+ assertFalse(this.nameIsBufferingModel.getValue().booleanValue());
+ }
+
+ public void testAdapterToString() {
+ PropertyChangeListener bufferedListener = this.buildBufferedListener();
+ this.bufferedNameModel.addPropertyChangeListener(PropertyValueModel.VALUE, bufferedListener);
+
+ Object adapter = ObjectTools.get(this.bufferedNameModel, "adapter");
+ String s = adapter.toString();
+ assertTrue(s.contains("(Freddy)"));
+
+ this.bufferedNameModel.setValue("Ripley");
+ assertEquals("Freddy", this.employee.getName());
+ assertEquals("Freddy", this.nameModel.getValue());
+ assertEquals("Ripley", this.bufferedNameModel.getValue());
+ assertTrue(this.nameIsBufferingModel.getValue().booleanValue());
+
+ s = adapter.toString();
+ assertTrue(s.contains("(Ripley [Freddy])"));
+ }
+
+ public void testTriggerToString() {
+ assertNotNull(this.trigger.toString());
+ }
+
+ public void testFactoryCtor_NPE1() {
+ boolean exCaught = false;
+ try {
+ Association<ModifiablePropertyValueModel<Integer>, PropertyValueModel<Boolean>> association = PropertyValueModelTools.buffer(null, this.trigger);
+ fail("bogus: " + association);
+ } catch (NullPointerException ex) {
+ exCaught = true;
+ }
+ assertTrue(exCaught);
+ }
+
+ public void testFactoryCtor_NPE2() {
+ boolean exCaught = false;
+ try {
+ Association<ModifiablePropertyValueModel<Integer>, PropertyValueModel<Boolean>> association = PropertyValueModelTools.buffer(this.idModel, null);
+ fail("bogus: " + association);
+ } catch (NullPointerException ex) {
+ exCaught = true;
+ }
+ assertTrue(exCaught);
+ }
+
+ private ChangeListener buildBufferedListener() {
+ return new ChangeAdapter() {
+ @Override
+ public void propertyChanged(PropertyChangeEvent e) {
+ BufferedPropertyValueModelTests.this.bufferedEvent = e;
+ }
+ };
+ }
+
+ private ChangeListener buildAdapterListener() {
+ return new ChangeAdapter() {
+ @Override
+ public void propertyChanged(PropertyChangeEvent e) {
+ BufferedPropertyValueModelTests.this.adapterEvent = e;
+ }
+ };
+ }
+
+ private ChangeListener buildEmployeeListener() {
+ return new ChangeAdapter() {
+ @Override
+ public void propertyChanged(PropertyChangeEvent e) {
+ BufferedPropertyValueModelTests.this.employeeEvent = e;
+ }
+ };
+ }
+
+ private void verifyEvent(PropertyChangeEvent event, Object source, String propertyName, Object oldValue, Object newValue) {
+ assertEquals(source, event.getSource());
+ assertEquals(propertyName, event.getPropertyName());
+ assertEquals(oldValue, event.getOldValue());
+ assertEquals(newValue, event.getNewValue());
+ }
+
+
+ // ********** Employee **********
+
+ class Employee
+ extends AbstractModel
+ {
+ private int id;
+ public static final String ID_PROPERTY = "id";
+ private String name;
+ public static final String NAME_PROPERTY = "name";
+ private Date hireDate;
+ public static final String HIRE_DATE_PROPERTY = "hireDate";
+
+ Employee(int id, String name, Date hireDate) {
+ super();
+ this.id = id;
+ this.name = name;
+ this.hireDate = hireDate;
+ }
+ int getID() {
+ return this.id;
+ }
+ void setID(int id) {
+ int old = this.id;
+ this.id = id;
+ this.firePropertyChanged(ID_PROPERTY, old, id);
+ }
+ String getName() {
+ return this.name;
+ }
+ void setName(String name) {
+ Object old = this.name;
+ this.name = name;
+ this.firePropertyChanged(NAME_PROPERTY, old, name);
+ }
+ Date getHireDate() {
+ return this.hireDate;
+ }
+ void setHireDate(Date hireDate) {
+ Object old = this.hireDate;
+ this.hireDate = hireDate;
+ this.firePropertyChanged(HIRE_DATE_PROPERTY, old, hireDate);
+ }
+ @Override
+ public void toString(StringBuilder sb) {
+ sb.append(this.name);
+ }
+ }
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/JptCommonUtilityModelValueTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/JptCommonUtilityModelValueTests.java
index 3a84dc44ef..be6e0220b3 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/JptCommonUtilityModelValueTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/JptCommonUtilityModelValueTests.java
@@ -22,7 +22,7 @@ public class JptCommonUtilityModelValueTests {
suite.addTest(JptCommonUtilityModelValuePrefsTests.suite());
suite.addTest(JptCommonUtilityModelValueSwingTests.suite());
- suite.addTestSuite(BufferedModifiablePropertyValueModelTests.class);
+ suite.addTestSuite(BufferedPropertyValueModelTests.class);
suite.addTestSuite(CachingTransformationPropertyValueModelTests.class);
suite.addTestSuite(CollectionAspectAdapterTests.class);
suite.addTestSuite(CollectionListValueModelAdapterTests.class);

Back to the top