ICE09 . playing with java, scala, groovy and spring .

Playing with Spring

Patters (cont’d): The Observer Pattern

Posted by ice09 on August 9, 2008

Download Eclipse project

I implemented the Observer Pattern with a central registry which is synchronized and uses WeakHashMaps, thereby trying to omit memory leaks.

The Notification Manager:

package observer;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class NotificationManager implements Observable {

	private Map<Integer, List<Observer>> observers = new WeakHashMap<Integer, List<Observer>>();

	private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
	private final Lock read = readWriteLock.readLock();
	private final Lock write = readWriteLock.writeLock();

	public void notifyObservers(Object source, Object arg) {
		List<Observer> obs = null;
		read.lock();
		try {
			if (!observers.containsKey(source.hashCode())) {
				return;
			} else {
				obs = observers.get(source.hashCode());
			}
			for (Observer observer : obs) {
				observer.update(arg);
			}
		} finally {
			read.unlock();
		}
	}

	public void register(Object target, Observer observer) {
		List<Observer> obs = null;
		write.lock();
		try {
			if (!observers.containsKey(target.hashCode())) {
				obs = new ArrayList<Observer>();
			} else {
				obs = observers.get(target.hashCode());
			}
			if (!obs.contains(observer)) {
				obs.add(observer);
			}
			observers.put(target.hashCode(), obs);
		} finally {
			write.unlock();
		}
	}

	public void remove(Object target, Observer observer) {
		List<Observer> obs = null;
		write.lock();
		try {
			if (!observers.containsKey(target.hashCode())) {
				return;
			} else {
				obs = observers.get(target.hashCode());
			}
			if (!obs.contains(observer)) {
				return;
			}
			obs.remove(observer);
		} finally {
			write.unlock();
		}
	}

	public String toString() {
		return "#Observers: ".concat(String.valueOf(observers.entrySet().size()));
	}

}

The Observer interface:

package observer;

public interface Observer {

	public void update(Object arg);

}

The Observable interface implemented by the NotificationManager:

package observer;

public interface Observable {

	public void register(Object target, Observer observer);
	public void remove(Object target, Observer observer);

	public void notifyObservers(Object source, Object arg);

}

The unit test class extending AbstractDependencyInjectionSpringContextTests:

package observer;

import org.springframework.test.AbstractDependencyInjectionSpringContextTests;

public class ObserverTest extends AbstractDependencyInjectionSpringContextTests implements Observer {

	protected NotificationManager notificationmanager;

	public ObserverTest() {
		setPopulateProtectedVariables(true);
	}

	public ObserverTest(String s) {
		super(s);
		setPopulateProtectedVariables(true);
	}

	public void testNM() {
		ObservableObject oo = new ObservableObject();
		notificationmanager.register(oo, this);
		oo.notifyObs();
		notificationmanager.remove(oo, this);
		oo.notifyObs();
	}

	@Override
	protected String[] getConfigLocations() {
		return new String[]{"applicationContext-test.xml"};
	}

	public void update(Object arg) {
		System.out.println("called with " + arg);
	}

	private class ObservableObject {

		public void notifyObs() {
			notificationmanager.notifyObservers(this, "bla");
		}

	}

}

The config, the notificationmanager is injected into the protected variable in the junit test:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>

	<bean id="notificationmanager" class="observer.NotificationManager"/>

</beans>
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: