View Javadoc

1   package cz.cuni.amis.utils.flag;
2   
3   import java.io.Serializable;
4   
5   /**
6    * Allows you to pass reasons of flag change along with new value of the flag.
7    * <p><p><p>
8    * This extension of Flag is MAGICAL! And I mean it ... it is correct from the point of view of OOP (asfaik),
9    * but the Flag alone is complex class and we're trying to hack another parameter to the setFlag() method!
10   * <p><p>
11   * Anyway, it works as you would expect it to work ;)
12   * 
13   * 
14   * @author Jimmy
15   *
16   * @param <TYPE>
17   * @param <REASON>
18   */
19  public class ReasonFlag<TYPE, REASON> extends Flag<TYPE> implements IReasonFlag<TYPE, REASON>, Serializable {
20  	
21  	class SetInSyncWithReason extends SetInSync {
22  		
23  		private REASON reason;
24  		
25  		public SetInSyncWithReason(TYPE newValue, REASON reason) {
26  			super(newValue);
27  			this.newValue = newValue;
28  			this.reason = reason;
29  		}
30  
31  		@Override
32  		public void execute(TYPE flagValue) {
33  			if (
34  				(newValue == null && flagValue != null)
35  				||
36  				!newValue.equals(flagValue)
37  		       ) {
38  				if (flag instanceof ImmutableFlag) throw new UnsupportedOperationException("trying to set flag of the immutable flag!");			
39  				flag.value = newValue;
40  				flag.notifier.setValue(newValue);
41  				if (flag instanceof ReasonFlag) {
42  					((ReasonFlagListener.ReasonFlagListenerNotifier)flag.notifier).setReason(reason);
43  					flag.listeners.notify(flag.notifier);
44  					// to clear the reason for normal "DoInSync" to work correctly.
45  					((ReasonFlagListener.ReasonFlagListenerNotifier)flag.notifier).setReason(null);
46  				} else {
47  					flag.listeners.notify(flag.notifier);
48  				}
49  			}
50  		}
51  		
52  	}
53  
54  	
55  	/**
56       * Initialize the flag without 'initialValue', initial value will be null.
57       */
58      public ReasonFlag() {
59      	this(null);    	
60      }
61  
62      /**
63       * Initialize the flag with 'initialValue'.
64       * @param initialValue
65       */
66      public ReasonFlag(TYPE initialValue) {
67      	super(initialValue);
68      	this.notifier = new ReasonFlagListener.ReasonFlagListenerNotifier<TYPE, REASON>();
69      }
70  
71  	/**
72       * Changes the flag and informs all listeners.
73       * <p><p>
74       * Should not produce any dead-locks even though it is synchronized method.
75       * 
76       * @param newValue
77       * @throws InterruptedRuntimeException if interrupted during the await on the freeze latch
78       */
79      public void setFlag(TYPE newValue, REASON reasonForChange) {
80      	inSyncInner(new SetInSyncWithReason(newValue, reasonForChange), false);
81      }
82      
83      /**
84       * Use {@link ReasonFlagListener} to get reasons or simple {@link FlagListener} to only receives
85       * new values.
86       * <p><p>
87       * {@link FlagListener} will be wrapped using {@link ReasonFlagListener.FlagListenerAdapter}
88       * <p><p>
89       * For more documentation see {@link Flag}
90       * 
91       * @param listener
92       */
93      @Override
94      public void addStrongListener(FlagListener<TYPE> listener) {
95         	super.addStrongListener(listener);
96      }
97          
98      /**
99       * Use {@link ReasonFlagListener} to get reasons or simple {@link FlagListener} to only receives
100      * new values.
101      * <p><p>
102      * {@link FlagListener} will be wrapped using {@link ReasonFlagListener.FlagListenerAdapter}
103      * <p><p>
104      * For more documentation see {@link Flag}. 
105      * <p><p>
106      * <b>WARNING:</b>The listener is stored via weak-reference!
107      * 
108      * @param listener
109      */
110     @Override
111     public void addListener(FlagListener<TYPE> listener) {
112        	super.addListener(listener);
113     }
114 
115     //
116     //
117     // TESTING OF THE CLASS!!!
118     //
119     //
120     
121     private static enum DummyReason {
122     	NEW,
123     	UPDATE,
124     	FAILURE;
125     }
126     
127     /**
128      * TEST METHOD! 
129      * <p><p>
130      * Test by eye :-(
131      */
132     public static void main(String[] args) {
133     	
134     	ReasonFlag<Boolean, DummyReason> flag = new ReasonFlag<Boolean, DummyReason>(false);
135     	
136     	ReasonFlagListener<Boolean, DummyReason> listener1 = new ReasonFlagListener<Boolean, DummyReason>() {
137 
138 			@Override
139 			public void flagChanged(Boolean changedValue, DummyReason reason) {
140 				System.out.println("1 -> " + changedValue + " because " + reason);
141 			}
142 
143 			@Override
144 			public void flagChanged(Boolean changedValue) {
145 				System.out.println("1 -> " + changedValue);				
146 			}
147     		
148     	};
149     	
150     	ReasonFlagListener<Boolean, DummyReason> listener2 = new ReasonFlagListener<Boolean, DummyReason>() {
151 
152 			@Override
153 			public void flagChanged(Boolean changedValue, DummyReason reason) {
154 				System.out.println("2 -> " + changedValue + " because " + reason);
155 			}
156 
157 			@Override
158 			public void flagChanged(Boolean changedValue) {
159 				System.out.println("2 -> " + changedValue);				
160 			}
161     		
162     	};
163     	
164     	FlagListener<Boolean> listener3 = new FlagListener<Boolean>() {
165 
166 			@Override
167 			public void flagChanged(Boolean changedValue) {
168 				System.out.println("3 -> " + changedValue);				
169 			}
170     		
171     	};
172     	
173     	flag.addListener(listener1);
174     	flag.addListener(listener2);
175     	flag.addListener(listener3);
176     	
177     	flag.setFlag(true);
178     	
179     	flag.setFlag(false, DummyReason.UPDATE);
180     	
181     	flag.setFlag(true);
182     	
183     	flag.setFlag(false, DummyReason.FAILURE);	
184     }
185 
186          /**
187      * @return Immutable version of this flag, setFlag(T) method of such
188      * a flag will raise an exception.
189      */
190     @Override
191     public ImmutableReasonFlag<TYPE, REASON> getImmutable() {
192         if (immutableWrapper == null) {
193             immutableWrapper = new ImmutableReasonFlag<TYPE, REASON>(this);
194         }
195         return (ImmutableReasonFlag)immutableWrapper;
196     }
197 	
198 }