From 7c279747beb43c7e88633a6228a155a30e6834f7 Mon Sep 17 00:00:00 2001 From: Benjamin Culkin Date: Mon, 27 May 2024 11:38:33 -0400 Subject: Initial import --- .../foundation/valuemodel/MutableValue.java | 23 ++++ .../israfil/foundation/valuemodel/Observable.java | 37 ++++++ .../net/israfil/foundation/valuemodel/Value.java | 22 ++++ .../israfil/foundation/valuemodel/ValueHolder.java | 108 ++++++++++++++++ .../israfil/foundation/valuemodel/Vetoable.java | 44 +++++++ .../foundation/valuemodel/ValueHolderTest.java | 143 +++++++++++++++++++++ 6 files changed, 377 insertions(+) create mode 100644 israfil-foundation-valuemodel/src/main/java/net/israfil/foundation/valuemodel/MutableValue.java create mode 100644 israfil-foundation-valuemodel/src/main/java/net/israfil/foundation/valuemodel/Observable.java create mode 100644 israfil-foundation-valuemodel/src/main/java/net/israfil/foundation/valuemodel/Value.java create mode 100644 israfil-foundation-valuemodel/src/main/java/net/israfil/foundation/valuemodel/ValueHolder.java create mode 100644 israfil-foundation-valuemodel/src/main/java/net/israfil/foundation/valuemodel/Vetoable.java create mode 100644 israfil-foundation-valuemodel/src/test/java/net/israfil/foundation/valuemodel/ValueHolderTest.java (limited to 'israfil-foundation-valuemodel/src') diff --git a/israfil-foundation-valuemodel/src/main/java/net/israfil/foundation/valuemodel/MutableValue.java b/israfil-foundation-valuemodel/src/main/java/net/israfil/foundation/valuemodel/MutableValue.java new file mode 100644 index 0000000..74d4dd1 --- /dev/null +++ b/israfil-foundation-valuemodel/src/main/java/net/israfil/foundation/valuemodel/MutableValue.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2003, Israfil Consulting Services Corporation + * + * $Id$ + * $Revision$ + * + */ +package net.israfil.foundation.valuemodel; + + +/** + * A smalltalk-style generic value accessor/mutator system, where individual + * items are accessed through a single value + * + * @author Original: Christian Edward Gruber + * @author Recent: $Author$ + * + */ +public interface MutableValue extends Value, Vetoable { + + public void set(E value); + +} diff --git a/israfil-foundation-valuemodel/src/main/java/net/israfil/foundation/valuemodel/Observable.java b/israfil-foundation-valuemodel/src/main/java/net/israfil/foundation/valuemodel/Observable.java new file mode 100644 index 0000000..574c8cf --- /dev/null +++ b/israfil-foundation-valuemodel/src/main/java/net/israfil/foundation/valuemodel/Observable.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2003-2007 Israfil Consulting Services Corporation + * Copyright (c) 2003-2007 Christian Edward Gruber + * All Rights Reserved + * + * $Id: Types.java 129 2006-12-31 23:20:02Z cgruber $ + */ +package net.israfil.foundation.valuemodel; + +/** + * An interface for objects that can notify observers of changes to itself. The + * changing object should call the provided callback signature, with the + * parameter being the object that was changed in its new state. + * + * Using a dynamic selector rather than a strong interface allows code + * to be notified of the change even if it was not constructed with the + * notification interface, though it does need to match the signature. + * + * @author Christian Edward Gruber + * @author Latest: $Author: cgruber $ + * @version $Revision: 129 $ + */ +public interface Observable { + + /** Add an observer to this object, with a callback method spec that will + * be invoked upon a data change. The callback method should contain three + * object parameters, one for the sender, one for the old value, and one for + * the new value. The meaning of the value (same object, copy, values, etc.) + * is left to the implementation object and the observers. + */ + public void addObservers(String callback, Object ... observers); + /** + * Remove observer from observable object. + */ + public void removeObservers(Object ... observers); + +} diff --git a/israfil-foundation-valuemodel/src/main/java/net/israfil/foundation/valuemodel/Value.java b/israfil-foundation-valuemodel/src/main/java/net/israfil/foundation/valuemodel/Value.java new file mode 100644 index 0000000..8c545bd --- /dev/null +++ b/israfil-foundation-valuemodel/src/main/java/net/israfil/foundation/valuemodel/Value.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2003, Israfil Consulting Services Corporation + * + * $Id$ + * $Revision$ + * + */ +package net.israfil.foundation.valuemodel; + +/** + * A smalltalk-style generic value accessor/mutator system, where individual + * items are accessed through a single value + * + * @author Original: Christian Edward Gruber + * @author Recent: $Author$ + * + */ +public interface Value extends Observable { + + public E get(); + +} diff --git a/israfil-foundation-valuemodel/src/main/java/net/israfil/foundation/valuemodel/ValueHolder.java b/israfil-foundation-valuemodel/src/main/java/net/israfil/foundation/valuemodel/ValueHolder.java new file mode 100644 index 0000000..55f23c3 --- /dev/null +++ b/israfil-foundation-valuemodel/src/main/java/net/israfil/foundation/valuemodel/ValueHolder.java @@ -0,0 +1,108 @@ +/* + * Created on Dec 8, 2003 + * + * To change the template for this generated file go to + * Window>Preferences>Java>Code Generation>Code and Comments + */ +package net.israfil.foundation.valuemodel; + +import java.util.HashMap; +import java.util.Map; + +import net.israfil.foundation.dynamic.DynamicUtil; + + +/** + * @author cgruber + * + * To change the template for this generated type comment go to + * Window>Preferences>Java>Code Generation>Code and Comments + */ +public class ValueHolder implements MutableValue { + + private E _value = null; + private Map _observers = new HashMap(); + private Map _vetoers = new HashMap(); + + public ValueHolder(E o) { + set(o); + } + + protected ValueHolder() { } + + public E get() { + return _value; + } + + public void set(E newValue) { + boolean approved = true; + E oldValue = _value; + for (VetoerHolder vetoer : _vetoers.values()) { + approved &= vetoer.evaluate(this, oldValue, newValue); + } + + if (!approved) return; + else _value = newValue; + for (ObserverHolder observer : _observers.values()) { + observer.notify(this, oldValue, newValue); + } + + } + + /** + * @see org.israfil.maveric.Observable#addObserver(java.lang.Object, java.lang.String) + */ + public void addObservers(String callback, Object ... observers) { + for (Object observer : observers) { + _observers.put(observer.hashCode(),new ObserverHolder(observer,callback)); + } + } + + /** + * @see org.israfil.maveric.Observable#removeObserver(java.lang.Object) + */ + public void removeObservers(Object ... observers) { + for (Object observer : observers) { + _observers.remove(observer.hashCode()); + } + } + /** + * @see org.israfil.maveric.Vetoable#addVetoer(java.lang.Object, java.lang.String) + */ + public void addVetoers(String callback, Object ... vetoers) { + for (Object vetoer : vetoers) { + _vetoers.put(vetoer.hashCode(),new VetoerHolder(vetoer,callback)); + } + } + + /** + * @see org.israfil.maveric.Vetoable#removeVetoer(java.lang.Object) + */ + public void removeVetoers(Object ... vetoers) { + for (Object vetoer : vetoers) { + _vetoers.remove(vetoer.hashCode()); + } + } + + protected class CallbackObjectHolder { + public final Object receiver; + protected final String callback; + public CallbackObjectHolder(Object receiver, String callback) { + this.receiver = receiver; + this.callback = callback; + } + } + protected class ObserverHolder extends CallbackObjectHolder { + public ObserverHolder(Object observer, String callback) { super(observer, callback); } + public void notify(Object notifier, Object oldValue, Object newValue) { + DynamicUtil.performOn(receiver,callback,new Object[]{notifier, oldValue , newValue}); + } + } + protected class VetoerHolder extends CallbackObjectHolder { + public VetoerHolder(Object vetoer, String callback) { super(vetoer, callback); } + public Boolean evaluate(Object notifier, Object oldValue, Object newValue) { + Boolean result = (Boolean)DynamicUtil.performOn(receiver,callback,new Object[]{notifier,oldValue,newValue}); + return (result == null) ? true : result.booleanValue(); + } + } +} diff --git a/israfil-foundation-valuemodel/src/main/java/net/israfil/foundation/valuemodel/Vetoable.java b/israfil-foundation-valuemodel/src/main/java/net/israfil/foundation/valuemodel/Vetoable.java new file mode 100644 index 0000000..5369287 --- /dev/null +++ b/israfil-foundation-valuemodel/src/main/java/net/israfil/foundation/valuemodel/Vetoable.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2003-2007 Israfil Consulting Services Corporation + * Copyright (c) 2003-2007 Christian Edward Gruber + * All Rights Reserved + * + * $Id: Types.java 129 2006-12-31 23:20:02Z cgruber $ + */ +package net.israfil.foundation.valuemodel; + +/** + * An interface for objects that can notify observers of changes to itself + * before the change. The objects thus notified can veto the change. The + * specific behaviour for vetoing is undefined and is dependent upon the + * particular implementation of the vetoable object and its vetoers. + * The changing object should call the provided callback signature, with the + * parameter being the object that was changed in its new state. The vetoer + * is responsible for knowing what it needs to know in order to validate or + * veto the change. + * + * Using a dynamic selector rather than a strong interface allows code + * to be notified of the change even if it was not constructed with the + * notification interface, though it does need to match the signature. + * + * @author Christian Edward Gruber + * @author Latest: $Author: cgruber $ + * @version $Revision: 129 $ + */ +public interface Vetoable { + + /** Add one or more vetoers to this object, with a callback method spec + * that will be invoked upon a data change. The callback method should + * contain three parameters. The first is the notification source (the + * holder or whatever), the second the old value, and the third the new + * value. It also should return a boolean approving the change (or + * returning false to veto it) + */ + public void addVetoers(String callback, Object ... approvers); + + /** + * Remove one or more vetoers from vetoable object. + */ + public void removeVetoers(Object ... approvers); + +} diff --git a/israfil-foundation-valuemodel/src/test/java/net/israfil/foundation/valuemodel/ValueHolderTest.java b/israfil-foundation-valuemodel/src/test/java/net/israfil/foundation/valuemodel/ValueHolderTest.java new file mode 100644 index 0000000..271c4a0 --- /dev/null +++ b/israfil-foundation-valuemodel/src/test/java/net/israfil/foundation/valuemodel/ValueHolderTest.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2003-2008Israfil Consulting Services Corporation + * Copyright (c) 2003-2008 Christian Edward Gruber + * All Rights Reserved + * + * $Id: Types.java 129 2006-12-31 23:20:02Z cgruber $ + */ +package net.israfil.foundation.valuemodel; + +import net.israfil.foundation.core.Copyright; + +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +/** + * Tests for ValueHolder + * + * @author Christian Edward Gruber + * @author Latest: $Author: cgruber $ + * @version $Revision: 129 $ + */ +@Copyright(years={"2003","2004","2005","2006","2007","2008"},owner="Israfil Consulting Services Corporation",license="BSD") +@Test +public class ValueHolderTest { + + private String stringValue = null; + private Integer integerValue = null; + private ValueHolder stringValueHolder = null; + private ValueHolder integerValueHolder = null; + + @BeforeMethod + protected void setUp() throws Exception { + stringValue = "String Value"; + integerValue = new Integer(5); + stringValueHolder = new ValueHolder(stringValue); + integerValueHolder = new ValueHolder(integerValue); + } + + @AfterMethod + protected void tearDown() throws Exception { + stringValue = null; + integerValue = null; + stringValueHolder = null; + integerValueHolder = null; + } + + /* + * Test for void ValueHolder(Object) + */ + public void testValueHolderObject() { + String valueString = "Value"; + ValueHoldervalueHolder = new ValueHolder(valueString); + Assert.assertEquals(valueString,valueHolder.get()); + } + + public void testGetValue() { + Assert.assertEquals(stringValue,stringValueHolder.get()); + Assert.assertEquals(integerValue,integerValueHolder.get()); + } + + public void testSetValueObject() { + String stringValue2 = "String Value 2"; + stringValueHolder.set(stringValue2); + Assert.assertEquals(stringValue2,stringValueHolder.get()); + } + + public void testAddObserverObjectString() { + String stringValue2 = "String Value 2"; + CallbackObject callback = new CallbackObject(stringValueHolder); + stringValueHolder.addObservers("notifyMe:java.lang.Object:java.lang.Object:java.lang.Object",callback); + stringValueHolder.set(stringValue2); + Assert.assertTrue(callback.notified); + } + public void testRemoveObserverObjectString() { + String stringValue2 = "String Value 2"; + CallbackObject callback = new CallbackObject(stringValueHolder); + stringValueHolder.addObservers("notifyMe:java.lang.Object:java.lang.Object:java.lang.Object",callback); + stringValueHolder.removeObservers(callback); + stringValueHolder.set(stringValue2); + Assert.assertFalse(callback.notified); + } + public void testAddApproverObjectString() { + String stringValue2 = "String Value 2"; + CallbackObject callback = new CallbackObject(stringValueHolder); + stringValueHolder.addVetoers("approve:java.lang.Object:java.lang.Object:java.lang.Object",callback); + stringValueHolder.set(stringValue2); + Assert.assertEquals(stringValue2,stringValueHolder.get()); + + callback = new CallbackObject(stringValueHolder); + stringValueHolder.addVetoers("approve:java.lang.Object:java.lang.Object:java.lang.Object",callback); + stringValueHolder.set(stringValue2); + stringValueHolder.set(stringValue); + Assert.assertEquals(stringValue2,stringValueHolder.get()); + Assert.assertFalse(stringValue.equals(stringValueHolder.get())); + } + public void testRemoveApproverObjectString() { + String stringValue2 = "String Value 2"; + CallbackObject callback = new CallbackObject(stringValueHolder); + stringValueHolder.addVetoers("approve:java.lang.Object:java.lang.Object:java.lang.Object",callback); + stringValueHolder.removeVetoers(callback); + stringValueHolder.set(stringValue2); + stringValueHolder.set(stringValue); + Assert.assertEquals(stringValue,stringValueHolder.get()); + Assert.assertFalse(stringValue2.equals(stringValueHolder.get())); + } + public void finalize() throws Throwable { + stringValue = null; + integerValue = null; + stringValueHolder = null; + integerValueHolder = null; + super.finalize(); + } + + public class CallbackObject { + private final MutableValue valueModel; + public boolean notified = false; + public Object oldValue = null; + public Object newValue = null; + public CallbackObject(MutableValue valueModel) { + this.valueModel = valueModel; + } + public void notifyMe(Object sender, Object oldValue, Object newValue) { + this.oldValue = oldValue; + this.newValue = newValue; + Assert.assertEquals(this.valueModel,sender); + notified = true; + } + public boolean approve(Object sender, Object oldValue, Object newValue) { + this.oldValue = oldValue; + this.newValue = newValue; + Assert.assertEquals(this.valueModel,sender); + if (!newValue.equals(stringValue)) return true; + return false; + } + public void finalize() throws Throwable { + this.oldValue = null; + this.newValue = null; + super.finalize(); + } + } +} -- cgit v1.2.3