I am trying to implement observer pattern in Java Swing application I am working on as my school project. I have these two very simple classes, one states as a singleton observable model and second is an observer.
Observable model:
public class Model extends Observable {
private static Model instance = null;
private File selectedImageFile;
private int colorsCount;
public static Logger LOG = Logger.getLogger(Model.class);
private Model() {
this.initialize();
}
private void initialize() {
addObserver(new ModelObserver());
}
public static Model instance() {
if (Model.instance == null) {
Model.instance = new Model();
}
return Model.instance;
}
public void setColorsCount(int colorsCount) {
this.colorsCount = colorsCount;
notifyObservers(Actions.COLORS_COUNT);
}
public void selectedImage(File imageFile) {
this.selectedImageFile = imageFile;
notifyObservers(Actions.SELECTED_IMAGE);
}
public enum Actions {
SELECTED_IMAGE, COLORS_COUNT
}
}
Observer
public class ModelObserver implements Observer {
public static Logger LOG = Logger.getLogger(ModelObserver.class);
#Override
public void update(Observable o, Object arg) {
if (arg instanceof Model.Actions) {
Model.Actions action = (Actions) arg;
switch (action) {
case SELECTED_IMAGE:
selectedImage();
break;
case COLORS_COUNT:
colorsCount();
break;
default:
LOG.warn("Not supported action: " + action);
break;
}
} else {
LOG.warn("Not supported action: " + String.valueOf(arg));
}
}
private void colorsCount() {
LOG.info("Colors count has been changed....");
}
private void selectedImage() {
LOG.info("Image has been changed....");
}
}
Everything works - Model instance register change but observers (only one in my case) are not notified. In a method ModeObserver.update(Observable o, Object arg) there is no mention that model has been changed. So my problem is that observers are not notified.
What am I doing wrong? Thank you.
You forgot to call setChanged() to mark the observable as changed, which is required by the notifyObservers to actually perform the notification.
Related
I have an situation when i have an Observer to be a also a subject.
So let's image with have two entites A and B.
When Changes occurs in A's Model other entites should know including B (C,D...Etc).
When Changes occurs in B's Model other entites should know including A (C,D...Etc).
By implmenting the Observer pattern in this way i get an infinite loop betteween A and B.
Is the observer pattren not implmented correctly or do i need another pattren to handle this kind of design ?
Any way her my implementation
public interface ISubject {
public void registreObserver(IObserver obs);
public void removeObserver(IObserver obs);
public void notifyObservers();
}
And the Observer Interface
public interface IObserver {
public void update(ISubject subject);
}
The Model
import java.util.ArrayList;
import java.util.List;
public class AModel implements ISubject {
private List<IObserver> listObservers = new ArrayList<>();
#Override
public void registreObserver(IObserver obs) {
listObservers.add(obs);
}
#Override
public void removeObserver(IObserver obs) {
listObservers.remove(obs);
}
public void loadData(){
notifyObservers();
}
#Override
public void notifyObservers() {
for (IObserver obv : listObservers) {
obv.update(AModel.this);
}
}
}
BModel
import java.util.ArrayList;
import java.util.List;
public class BModel implements ISubject {
private List<IObserver> listObservers = new ArrayList<>();
#Override
public void registreObserver(IObserver obs) {
listObservers.add(obs);
}
#Override
public void removeObserver(IObserver obs) {
listObservers.remove(obs);
}
public void loadData(){
notifyObservers();
}
#Override
public void notifyObservers() {
for (IObserver obv : listObservers) {
obv.update(BModel.this);
}
}
}
The A controller
public class AController implements IObserver {
private AModel model;
public void setModel(AModel model) {
this.model = model;
}
#Override
public void update(ISubject subject) {
System.out.println(" A Changed");
model.loadData();
}
}
The B controller
public class BController implements IObserver {
private BModel model;
public void setModel(BModel model) {
this.model = model;
}
#Override
public void update(ISubject subject) {
System.out.println(" B Changed");
model.loadData();
}
}
Main Program
public class Main {
public static void main(String[] args) {
AModel aModel = new AModel();
AModel bModel = new BModel();
AController aController = new AController();
aController.setModel(aModel);
AController bController = new BController();
bController.setModel(bModel);
aModel.registreObserver(bController);
bModel.registreObserver(aController);
// Here the updates starts a notify b and b notify a and so on
aModel.notifyObservers();
}
}
The reason why you are getting an infinite loop is because each time you update your Observable, you notify its observers, but this notifying process then updates the model again and so it repeats.
Here is an example of how to use the Observer pattern in the way you are looking for:
import java.util.Observable;
import java.util.Observer;
public class Example {
public static void main(String[] args) {
Model modelA = new Model();
Model modelB = new Model();
Observer aController = (observable, arg) -> {
System.out.println("A controller: " + arg);
};
Observer bController = (observable, arg) -> {
System.out.println("B controller: " + arg);
};
modelA.addObserver(bController);
modelB.addObserver(aController);
modelA.update("test");
modelB.update("test2");
}
}
class Model extends Observable {
private String data;
public void update(String data) {
this.data = data;
setChanged();
notifyObservers(data);
}
}
Output:
B controller: test
A controller: test2
Although #arizzle's answer works, I think you are misusing the Observer pattern.
Observer
Define a one-to-many dependency between objects so that when one object changes > state, all its dependents are notified and updated automatically.
Source
Your problem seems more like a many-to-many relationship. In this case, I'd recomend you to use the Mediator Pattern to hide this complexity.
This is the canonic UML Diagram for this pattern:
I'll skip the interface/abstract class definition here to avoid bloating the answer.
Basic implementation:
class Mediator {
private Map<String, Colleague> participants = new HashMap<String, Colleague>();
public void register(Colleague c) {
participants.put(c.getName(), c);
c.setMediator(this);
}
public void send(Colleague from, String message, String to) {
Colleague c = participants.get(to);
if (c != null && c != from) {
c.receive(message, from);
}
}
public void send(Colleague from, String message) {
for (Map.Entry<String, Colleague> e: participants.entrySet()) {}
Colleague c = e.getValue();
if (c != from)) {
c.receive(message, from);
}
}
}
}
abstract class Colleague {
private Mediator mediator;
private String name;
public Colleague(String name) {
this.name = name;
}
public void setMediator(Mediator mediator) {
this.mediator = mediator;
}
public void send(String msg, String to) {
this.mediator.send(this, msg, to);
}
public void send(String msg) {
this.mediator.send(this, msg);
}
abstract public void receive(String msg, Colleague from);
}
class ConcreteColleague1 {
public void receive(String msg, String from) {
// do something
System.out.println("Received msg: " + msg + " from: " + from.getName());
}
}
class ConcreteColleague2 {
public void receive(String msg, String from) {
// do other thing
System.out.println("Received msg: " + msg + " from: " + from.getName());
}
}
Using it:
Mediator m = new Mediator();
Colleague c1 = new ConcreteColleague1('foo');
Colleague c2 = new ConcreteColleague2('bar');
Colleague c3 = new ConcreteColleague1('baz');
c1.send("test");
c2.send("test");
c3.send("test");
Will print:
"Received msg: test from: foo"
"Received msg: test from: foo"
"Received msg: test from: bar"
"Received msg: test from: bar"
"Received msg: test from: baz"
"Received msg: test from: baz"
This way, when you broadcast a message, you can know for sure that everyone received it, so you don't need to make another broadcast for each colleague to communicate the new state.
I'm using a multiplayer Game Client that's called AppWarp (http://appwarp.shephertz.com), where you can add event listeners to be called back when event's happen, let's assume we'll be talking about the Connection Listener, where you need to implement this interface:
public interface ConnectionRequestListener {
void onConnectDone(ConnectEvent var1);
void onDisconnectDone(ConnectEvent var1);
void onInitUDPDone(byte var1);
}
My goal here is to mainly create a Reactive version of this client to be used in my Apps Internally instead of using the Client itself directly (I'll also rely on interfaces later instead of just depending on the WarpClient itself as in the example, but that's not the important point, please read my question at the very end).
So what I did is as follows:
1) I introduced a new event, named it RxConnectionEvent (Which mainly groups Connection-Related events) as follows:
public class RxConnectionEvent {
// This is the original connection event from the source client
private final ConnectEvent connectEvent;
// this is to identify if it was Connection / Disconnection
private final int eventType;
public RxConnectionEvent(ConnectEvent connectEvent, int eventType) {
this.connectEvent = connectEvent;
this.eventType = eventType;
}
public ConnectEvent getConnectEvent() {
return connectEvent;
}
public int getEventType() {
return eventType;
}
}
2) Created some event types as follows:
public class RxEventType {
// Connection Events
public final static int CONNECTION_CONNECTED = 20;
public final static int CONNECTION_DISCONNECTED = 30;
}
3) Created the following observable which emits my new RxConnectionEvent
import com.shephertz.app42.gaming.multiplayer.client.WarpClient;
import com.shephertz.app42.gaming.multiplayer.client.events.ConnectEvent;
import rx.Observable;
import rx.Subscriber;
import rx.functions.Action0;
import rx.subscriptions.Subscriptions;
public class ConnectionObservable extends BaseObservable<RxConnectionEvent> {
private ConnectionRequestListener connectionListener;
// This is going to be called from my ReactiveWarpClient (Factory) Later.
public static Observable<RxConnectionEvent> createConnectionListener(WarpClient warpClient) {
return Observable.create(new ConnectionObservable(warpClient));
}
private ConnectionObservable(WarpClient warpClient) {
super(warpClient);
}
#Override
public void call(final Subscriber<? super RxConnectionEvent> subscriber) {
subscriber.onStart();
connectionListener = new ConnectionRequestListener() {
#Override
public void onConnectDone(ConnectEvent connectEvent) {
super.onConnectDone(connectEvent);
callback(new RxConnectionEvent(connectEvent, RxEventType.CONNECTION_CONNECTED));
}
#Override
public void onDisconnectDone(ConnectEvent connectEvent) {
super.onDisconnectDone(connectEvent);
callback(new RxConnectionEvent(connectEvent, RxEventType.CONNECTION_DISCONNECTED));
}
// not interested in this method (for now)
#Override
public void onInitUDPDone(byte var1) { }
private void callback(RxConnectionEvent rxConnectionEvent)
{
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(rxConnectionEvent);
} else {
warpClient.removeConnectionRequestListener(connectionListener);
}
}
};
warpClient.addConnectionRequestListener(connectionListener);
subscriber.add(Subscriptions.create(new Action0() {
#Override
public void call() {
onUnsubscribed(warpClient);
}
}));
}
#Override
protected void onUnsubscribed(WarpClient warpClient) {
warpClient.removeConnectionRequestListener(connectionListener);
}
}
4) and finally my BaseObservable looks like the following:
public abstract class BaseObservable<T> implements Observable.OnSubscribe<T> {
protected WarpClient warpClient;
protected BaseObservable (WarpClient warpClient)
{
this.warpClient = warpClient;
}
#Override
public abstract void call(Subscriber<? super T> subscriber);
protected abstract void onUnsubscribed(WarpClient warpClient);
}
My question is mainly: is my implementation above correct or should I instead create separate observable for each event, but if so, this client has more than 40-50 events do I have to create separate observable for each event?
I also use the code above as follows (used it in a simple "non-final" integration test):
public void testConnectDisconnect() {
connectionSubscription = reactiveWarpClient.createOnConnectObservable(client)
.subscribe(new Action1<RxConnectionEvent>() {
#Override
public void call(RxConnectionEvent rxEvent) {
assertEquals(WarpResponseResultCode.SUCCESS, rxEvent.getConnectEvent().getResult());
if (rxEvent.getEventType() == RxEventType.CONNECTION_CONNECTED) {
connectionStatus = connectionStatus | 0b0001;
client.disconnect();
} else {
connectionStatus = connectionStatus | 0b0010;
connectionSubscription.unsubscribe();
haltExecution = true;
}
}
}, new Action1<Throwable>() {
#Override
public void call(Throwable throwable) {
fail("Unexpected error: " + throwable.getMessage());
haltExecution = true;
}
});
client.connectWithUserName("test user");
waitForSomeTime();
assertEquals(0b0011, connectionStatus);
assertEquals(true, connectionSubscription.isUnsubscribed());
}
I suggest you avoid extending the BaseObservable directly since it's very error prone. Instead, try using the tools Rx itself gives you to create your observable.
The easiest solution is using a PublishSubject, which is both an Observable and a Subscriber. The listener simply needs to invoke the subject's onNext, and the subject will emit the event. Here's a simplified working example:
public class PublishSubjectWarpperDemo {
public interface ConnectionRequestListener {
void onConnectDone();
void onDisconnectDone();
void onInitUDPDone();
}
public static class RxConnectionEvent {
private int type;
public RxConnectionEvent(int type) {
this.type = type;
}
public int getType() {
return type;
}
public String toString() {
return "Event of Type " + type;
}
}
public static class SimpleCallbackWrapper {
private final PublishSubject<RxConnectionEvent> subject = PublishSubject.create();
public ConnectionRequestListener getListener() {
return new ConnectionRequestListener() {
#Override
public void onConnectDone() {
subject.onNext(new RxConnectionEvent(1));
}
#Override
public void onDisconnectDone() {
subject.onNext(new RxConnectionEvent(2));
}
#Override
public void onInitUDPDone() {
subject.onNext(new RxConnectionEvent(3));
}
};
}
public Observable<RxConnectionEvent> getObservable() {
return subject;
}
}
public static void main(String[] args) throws IOException {
SimpleCallbackWrapper myWrapper = new SimpleCallbackWrapper();
ConnectionRequestListener listner = myWrapper.getListener();// Get the listener and attach it to the game here.
myWrapper.getObservable().observeOn(Schedulers.newThread()).subscribe(event -> System.out.println(event));
listner.onConnectDone(); // Call the listener a few times, the observable should print the event
listner.onDisconnectDone();
listner.onInitUDPDone();
System.in.read(); // Wait for enter
}
}
A more complex solution would be to use one of the onSubscribe implementations to create an observable using Observable.create(). For example AsyncOnSubscibe. This solution has the benefit of handling backperssure properly, so your event subscriber doesn't become overwhelmed with events. But in your case, that sounds like an unlikely scenario, so the added complexity is probably not worth it.
first of all i am new to threads and shared variables. So please be kind with me ;-)
I'm having a class called Routing. This class recieves and handles messages. If a message is of type A the Routing-Object should pass it to the ASender Object which implements the Runnable Interface. If the message is of type B the Routing-Class should pass it to the BSender Object.
But the ASender and BSender Objects have common variables, that should be stored into the Routing-Object.
My idea now is to declare the variables as synchronized/volatile in the Routing-Object and the getter/setter also.
Is this the right way to synchronize the code? Or is something missing?
Edit: Added the basic code idea.
RoutingClass
public class Routing {
private synchronized Hashtable<Long, HashSet<String>> reverseLookup;
private ASender asender;
private BSender bsender;
public Routing() {
//Constructor work to be done here..
reverseLookup = new Hashtable<Long, HashSet<String>>();
}
public void notify(TopicEvent event) {
if (event.getMessage() instanceof AMessage) {
asender = new ASender(this, event.getMessage())
} else if (event.getMessage() instanceof BMessage) {
bsender = new BSender(this, event.getMessage())
}
}
public synchronized void setReverseLookup(long l, Hashset<String> set) {
reverseLookup.put(l, set);
}
public synchronized Hashtable<Long, Hashset<String>> getReverseLookup() {
return reverseLookup;
}
}
ASender Class
public class ASender implements Runnable {
private Routing routing;
private RoutingMessage routingMessage;
public ASender(Routing r, RoutingMessage rm) {
routing = r;
routingMessage = rm;
this.run();
}
public void run() {
handleMessage();
}
private void handleMessage() {
// do some stuff and extract data from the routing message object
routing.setReverseLookup(somethingToSet)
}
}
Some comments:
Hashtable is a thread-safe implementation, you do not need another "synchronized" keyword see this and this for more information
Avoid coupling, try to work with interfaces or pass the hashtable to your senders, see this for more information
Depending on the amount of senders, you might want to use a ConcurrentHashMap, it greatly improves the performance, see ConcurrentHashMap and Hashtable in Java and Java theory and practice: Concurrent collections classes
This would conclude something like...:
public interface IRoutingHandling {
void writeMessage(Long key, HashSet<String> value);
}
public class Routing implements IRoutingHandling {
private final Hashtable<Long, HashSet<String>> reverseLookup;
private ASender asender;
private BSender bsender;
public Routing() {
//Constructor work to be done here..
reverseLookup = new Hashtable<Long, HashSet<String>>();
}
public void notify(TopicEvent event) {
if (event.getMessage() instanceof AMessage) {
asender = new ASender(this, event.getMessage())
} else if (event.getMessage() instanceof BMessage) {
bsender = new BSender(this, event.getMessage())
}
}
#Override
public void writeMessage(Long key, HashSet<String> value) {
reverseLookup.put(key, value);
}
}
public class ASender implements Runnable {
private IRoutingHandling _routingHandling;
public ASender(IRoutingHandling r, RoutingMessage rm) {
_routingHandling = r;
routingMessage = rm;
this.run();
}
public void run() {
handleMessage();
}
private void handleMessage() {
// do some stuff and extract data from the routing message object
_routingHandling.writeMessage(somethingToSetAsKey, somethingToSetAsValue)
}
}
I'm trying to figure out how to listen to a property change in another class. Below is my code:
ClassWithProperty has the property I want to listen to:
public class ClassWithProperty {
private PropertyChangeSupport changes = new PropertyChangeSupport(this);
private int usersOnline;
public int getUsersOnline() {
return usersOnline;
}
public ClassWithProperty() {
usersOnline = 0;
while (usersOnline<10) {
changes.firePropertyChange("usersOnline", usersOnline, usersOnline++);
}
}
public void addPropertyChangeListener(
PropertyChangeListener l) {
changes.addPropertyChangeListener(l);
}
public void removePropertyChangeListener(
PropertyChangeListener l) {
changes.removePropertyChangeListener(l);
}
}
Main is where i need to know about the property change:
public class Main {
private static ClassWithProperty test;
public static void main(String[] args) {
test = new ClassWithProperty();
test.addPropertyChangeListener(listen());
}
private static PropertyChangeListener listen() {
System.out.println(test.getUsersOnline());
return null;
}
}
I have the event fired only the last time (usersOnline=10).
I'm new to Java and tried to find a solution, but to no avail.
The code:
private static PropertyChangeListener listen() {
System.out.println(test.getUsersOnline());
return null;
}
returns null which means "no object", which in turn means that test.addPropertyChangeListener(listen()) is effectively test.addPropertyChangeListener(null), which won't register anything.
You must pass a valid instance of a PropertyChangeListener to the addPropertyChangeListener() method.
Edit
I suggest you read the Java tutorial's chapter about PropertyChangeListeners:
http://download.oracle.com/javase/tutorial/uiswing/events/propertychangelistener.html
Another problem of your code is that you call firePropertyChange() in the constructor of ClassWithProperty. But at that time, no listener can possibly be registered, so it does not have any effect. Any call to addPropertyChangeListener() happens after you have fired the events.
Here is your code modified so that it should work (haven't tested it though...):
public class ClassWithProperty {
private PropertyChangeSupport changes = new PropertyChangeSupport(this);
private int usersOnline = 0;
public ClassWithProperty() {
}
public void setupOnlineUsers()
{
while (usersOnline < 10) {
changes.firePropertyChange("usersOnline", usersOnline, ++usersOnline);
}
}
public int getUsersOnline() {
return usersOnline;
}
public void addPropertyChangeListener(PropertyChangeListener l) {
changes.addPropertyChangeListener(l);
}
public void removePropertyChangeListener(PropertyChangeListener l) {
changes.removePropertyChangeListener(l);
}
}
public class MainListener implements PropertyChangeListener {
private ClassWithProperty test;
public MainListener() {
test = new ClassWithProperty();
test.addPropertyChangeListener(this);
test.setupOnlineUsers();
}
public void propertyChange(PropertyChangeEvent evt) {
System.out.println(test.getUsersOnline());
}
public static void main(String[] args) {
new MainListener(); // do everything in the constructor
}
}
What I do is put a method in the ClassWithProperty class:
public PropertyChangeSupport getPropertyChangeSupport() {
return changes;
}
Then, register for property change events in the constructor of your Main() class:
private void initializeListeners() {
test.getPropertyChangeSupport().addPropertyChangeListener((PropertyChangeEvent event) -> {
if (event.getPropertyName().equals("usersOnline")) {
String passedEventData = (String) event.getNewData();
}
});
}
This make it so you are not repeating the code in your ClassWithProperty with methods that are already in the PropertyChangeSupport class.
when you need to fire an event in your ClassWithProperty class, do:
changes.firePropertyChange("usersOnline", oldValue, newValue);
One notable feature of this method is that, if the
event.getOldValue() and the event.getNewValue()
are equal, the event will not fire. If you want to fire repeated events with the same information, use null in the oldValue field;
The firePropertyChange() method only passes int, boolean and Object. So if you are not passing an int or boolean, you need to cast the value that was passed in the event on the receiving end.
Your method here:
public ClassWithProperty() {
usersOnline = 0;
while (usersOnline<10) {
changes.firePropertyChange("usersOnline", usersOnline, usersOnline++);
usersOnline++;
}
}
has a while loop that will continuously loop and block the thread. My limited knowledge of property change listeners is that they listen for changes to a bound property, here the usersOnLine variable, meaning the property change should only fire if this number changes (likely within in any setUserOnLine, addUserOnLine, removeUserOnLine and similar methods). For more on bound properties, please look here: Bound Properties
In my web app, during some change over the object, i need to send a mail about the changes happened in the object.
My question is how to write a listener for this.
Please give me some article regarding this.
Thanks
A typical implementation could be like this: your object is observable. So every time, one of the (observed) values changes, an event is fired and all registered listeners are notified. One of those listeners now would be designed to take the notification and create and send an EMail (Java Mail API)
Let's take a sample bean which we make observable:
public class Bean implements Observable{
// code to maintain listeners
private List<Listener> listeners = new ArrayList<Listener>();
public void add(Listener listener) {listeners.add(listener);}
public void remove(Listener listener) {listeners.remove(listener);}
// a sample field
private int field;
public int getField() {return field;}
public int setField(int value) {
field = value;
fire("field");
}
// notification code
private void fire(String attribute) {
for (Listener listener:listeners) {
fieldChanged(this, attribute);
}
}
}
The Listener interface:
public interface Listener {
public void fieldChanged(Object source, String attrbute);
}
The Observable interface:
public interface Observable {
public void add(Listener listener);
public void remove(Listener listener);
}
And the EMailer:
public class Sender implements Listener {
public void register(Observable observable) {observable.add(this);}
public void unregister(Observable observable) {observable.remove(this);}
public void fieldChanged(Object source, String attribute) {
sendEmail(source, attribute); // this has to be implemented
}
}
EDIT
Corrected an ugly mistake in the setter method - now the event is fired after the property has been set. Was the other way round, with the side effect, that if a listener read the changed property, he still saw the old, unchanged value...
If you simply wish to know about the properties of an object being modified I would recommend using a PropertyChangeListener. That way you can use the PropertyChangeSupport utility class to manage your listener instances and the firing of events. You also avoid reinventing the wheel.
For more bespoke event firing I would recommend defining your own listener interface.
Example Class
public class MyBean {
private final PropertyChangeSupport support;
private int i;
private boolean b;
public MyBean() {
this.support = new PropertyChangeSupport(this);
}
// Accessors and Mutators. Mutating a property causes a PropertyChangeEvent
// to be fired.
public int getI() { return i; }
public void setI(int i) {
int oldI = this.i;
this.i = i;
support.firePropertyChange("i", oldI, this.i);
}
public boolean getB() { return b; }
public void setB(boolean b) {
boolean oldB = this.b;
this.b = b;
support.firePropertyChange("b", oldB, this.b);
}
// Wrapper methods that simply delegate listener management to
// the underlying PropertyChangeSupport class.
public void addPropertyChangeListener(PropertyChangeListener l) {
support.addPropertyChangeListener(l);
}
public void addPropertyChangeListener(String propertyName, PropertyChangeListener l) {
// You would typically call this method rather than addPropertyChangeListener(PropertyChangeListener)
// in order to register your listener with a specific property.
// This then avoids the need for large if-then statements within your listener
// implementation in order to check which property has changed.
if (!"i".equals(propertyName) && !"b".equals(propertyName)) {
throw new IllegalArgumentException("Invalid property name: " + propertyName);
}
support.addPropertyChangeListener(propertyName, l);
}
public void removePropertyChangeListener(PropertyChangeListener l) {
support.removePropertyChangeListener(l);
}
public void removePropertyChangeListener(String propertyName, PropertyChangeListener l) {
support.removePropertyChangeListener(propertyName, l);
}
}
Example Usage
// Create a new instance of our observable MyBean class.
MyBean bean = new MyBean();
// Create a PropertyChangeListener specifically for listening to property "b".
PropertyChangeListener listener = new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
assert "b".equals(evt.getPropertyName());
boolean oldB = (Boolean) evt.getOldValue();
boolean newB = (Boolean) evt.getNewValue();
System.err.println(String.format("Property b updated: %b -> %b, oldB, newB));
}
}
// Register listener with specific property name. It will only be called back
// if this property changes, *not* the "i" int property.
bean.addPropertyChangeListener("b", listener);
You should use the Observer Design Pattern. This pattern uses these classes :
java.util.Observable
java.util.Observer
Here is an example.
The observer :
public class EmailObserver implements Observer
{
#Override
public void update(Observable obj, Object arg)
{
if (obj instanceof YourObject)
{
// TODO Send the mail or whatever, you have access to the modified object through obj
// In arg you can put some additional parameter, like the modified field
}
}
}
The Observable Object :
public static class YourObject extends Observable
{
public void setSomething(Object parameter)
{
// TODO some modification in YourObject
setChanged(); // From Observable : the object has changed
notifyObservers(parameter); // Notify the observer about the change
}
}
And the main class :
public static void main(String[] args)
{
// Create YourObject
YourObject o = new YourObject();
// create an observer
EmailObserver emailObserver = new EmailObserver();
// subscribe the observer to your object
o.addObserver(emailObserver);
// Now you can modify your object, changes will be notified by email
o.setSomething(...);
}
Use Observer design pattern http://en.wikipedia.org/wiki/Observer_pattern.
http://java-x.blogspot.com/2007/01/implementing-observer-pattern-in-java.html