View Javadoc

1   /*
2    * EL4J, the Extension Library for the J2EE, adds incremental enhancements to
3    * the spring framework, http://el4j.sf.net
4    * Copyright (C) 2006 by ELCA Informatique SA, Av. de la Harpe 22-24,
5    * 1000 Lausanne, Switzerland, http://www.elca.ch
6    *
7    * EL4J is published under the GNU Lesser General Public License (LGPL)
8    * Version 2.1. See http://www.gnu.org/licenses/
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13   * GNU Lesser General Public License for more details.
14   *
15   * For alternative licensing, please contact info@elca.ch
16   */
17  package ch.elca.el4j.util.observer.impl;
18  
19  
20  import java.util.LinkedList;
21  import java.util.List;
22  
23  import ch.elca.el4j.util.codingsupport.Reject;
24  import ch.elca.el4j.util.codingsupport.annotations.ImplementationAssumption;
25  import ch.elca.el4j.util.observer.InquisitiveValueObserver;
26  import ch.elca.el4j.util.observer.ObservableValue;
27  import ch.elca.el4j.util.observer.ValueObserver;
28  
29  /**
30   * Abstract ObservableValue featuring value and observer storage as well as
31   * notification.
32   *
33   * @param <T> see supertype.
34   *
35   * @svnLink $Revision: 3873 $;$Date: 2009-08-04 13:59:45 +0200 (Di, 04. Aug 2009) $;$Author: swismer $;$URL: https://el4j.svn.sourceforge.net/svnroot/el4j/branches/el4j_3_1/el4j/framework/modules/core/src/main/java/ch/elca/el4j/util/observer/impl/AbstractObservableValue.java $
36   *
37   * @author Adrian Moos (AMS)
38   */
39  public abstract class AbstractObservableValue<T> implements ObservableValue<T> {
40  	/** no comment ... */
41  	private static class ValueHolder<T> {
42  		/** the value held by this. */
43  		private T m_value;
44  	}
45  	
46  	/** a holder for the current reference or {@code null},
47  	 * if there isn't one yet. */
48  	private ValueHolder<T> m_holder = null;
49  	
50  	/** the currently subscribed observers. */
51  	private List<ValueObserver<? super T>> m_obs
52  		= new LinkedList<ValueObserver<? super T>>();
53  
54  	/** creates a new ObservableValue. Subclasses must invoke
55  	 * {@link #set(Object)} to
56  	 * set the initial reference before {@link #get()} is invoked. */
57  	protected AbstractObservableValue() { }
58  	
59  	/** creates a new ObservableValue.
60  	 * @param initialReference the observable's initial value
61  	 **/
62  	public AbstractObservableValue(T initialReference) {
63  		set(initialReference);
64  	}
65  	
66  	/**
67  	 * {@inheritDoc}
68  	 */
69  	public void subscribeSilently(ValueObserver<? super T> o) {
70  		Reject.ifNull(o);
71  		m_obs.add(o);
72  	}
73  	
74  	/**
75  	 * {@inheritDoc}
76  	 */
77  	public void subscribe(ValueObserver<? super T> o) {
78  		subscribeSilently(o);
79  		if (m_holder != null) {
80  			o.changed(m_holder.m_value);
81  		}
82  	}
83  	
84  	/**
85  	 * {@inheritDoc}
86  	 */
87  	public void unsubscribe(ValueObserver<? super T> o) {
88  		m_obs.remove(o);
89  	}
90  	
91  	/** informs the subscribed observers. */
92  	@ImplementationAssumption(
93  		"An observer processing a notification never unsubscribes "
94  		+ "(directly or indirectly) a yet-to-be-notified observer.")
95  	private void announce() {
96  		List<ValueObserver<? super T>> observersSnapshot
97  			= new LinkedList<ValueObserver<? super T>>(m_obs);
98  		for (ValueObserver<? super T> o : observersSnapshot) {
99  			o.changed(m_holder.m_value);
100 		}
101 		for (ValueObserver<? super T> o : observersSnapshot) {
102 			if (o instanceof InquisitiveValueObserver<?>) {
103 				InquisitiveValueObserver<? super T> ivo
104 					= (InquisitiveValueObserver<? super T>) o;
105 				// don't we all love the tersity of generics? ;)
106 				
107 				ivo.notified();
108 			}
109 		}
110 	}
111 	
112 	/** updates this observer's current value and announces the change. */
113 	protected void set(T newValue) {
114 		if (m_holder != null) {
115 			if (equal(m_holder.m_value, newValue)) { return; }
116 		} else {
117 			m_holder = new ValueHolder<T>();
118 		}
119 		m_holder.m_value = newValue;
120 		announce();
121 	}
122 	
123 	/**
124 	 * {@inheritDoc}
125 	 */
126 	public T get() throws IllegalStateException {
127 		LiveValue.observableGetterInterceptor(this);
128 		if (m_holder == null) {
129 			throw new IllegalStateException(
130 				"reference does not exist yet."
131 			);
132 		}
133 		return m_holder.m_value;
134 	}
135 	
136 	
137 	/** defines when two references are considered equal. */
138 	// Is not static in order to enable overriding.
139 	protected boolean equal(T a, T b) {
140 		if (a == null) {
141 			return b == null;
142 		} else {
143 			return a.equals(b);
144 		}
145 	}
146 }