KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > oddjob > structural > StatefulChildHelper


1 package org.oddjob.structural;
2
3 import java.io.PrintStream JavaDoc;
4 import java.util.HashMap JavaDoc;
5 import java.util.Iterator JavaDoc;
6 import java.util.Map JavaDoc;
7
8 import org.oddjob.Stateful;
9 import org.oddjob.state.JobState;
10 import org.oddjob.state.JobStateEvent;
11 import org.oddjob.state.JobStateHandler;
12 import org.oddjob.state.JobStateListener;
13
14 /**
15  * A version of a child helper which also monitors state.
16  *
17  * @author Rob Gordon
18  */

19
20 public class StatefulChildHelper extends ChildHelper
21 implements Stateful {
22
23     /** Stops firing events while we're loading */
24     private boolean initialised;
25     
26     /** Stateful listeners. Remember the listeners so
27      * we can remove them later. The object will be either the true
28      * child or a wrapper. */

29     private final Map JavaDoc /*<Object, JobStateListener>*/ listeners = new HashMap JavaDoc();
30
31     /**
32      * The job states. Mapped so we can remove job states when
33      * a job is removed. The object will always be the true child not a wrapper.
34      */

35     private final Map JavaDoc /*<Object, JobStateEvent>*/jobStates = new HashMap JavaDoc();
36     
37     private final JobStateHandler stateHandler = new JobStateHandler(this);
38     
39     
40     public StatefulChildHelper(Object JavaDoc source) {
41         super(source);
42     }
43     
44     public void initialise() {
45         initialised = true;
46     }
47     
48     /**
49      * Helper method that provides the child to add to the structure.
50      * This method will add a listener to the child so we can track
51      * it's state.
52      *
53      * @param child The child.
54      * @return A child to add to the structure.
55      */

56     private void addStateListener(Object JavaDoc child) {
57         if (child instanceof Stateful) {
58             synchronized (jobStates) {
59                 ChildStateListener l = new ChildStateListener(child);
60                 listeners.put(child, l);
61                 ((Stateful) child).addJobStateListener(l);
62             }
63         }
64     }
65     
66     /**
67      * Add a child. This method
68      *
69      *
70      * @param child A child object.
71      */

72     public void addChild(Object JavaDoc child) {
73         if (child == null) {
74             throw new NullPointerException JavaDoc("Attempt to add a null child.");
75         }
76         addStateListener(child);
77         super.addChild(child);
78     }
79
80     public void insertChild(int index, Object JavaDoc child) {
81         if (child == null) {
82             throw new NullPointerException JavaDoc("Attempt to add a null child.");
83         }
84
85         addStateListener(child);
86         super.insertChild(index, child);
87     }
88
89     /**
90      * Remove a listener.
91      *
92      * @param index The position of the listener.
93      */

94     private void removeStateListenerAt(int index) {
95         synchronized (jobStates) {
96             Object JavaDoc child = getChildAt(index);
97             if (child instanceof Stateful) {
98                 ChildStateListener l = (ChildStateListener) listeners.remove(child);
99                 ((Stateful) child).removeJobStateListener(l);
100                 jobStates.remove(child);
101             }
102         }
103     }
104     
105     /**
106      * Remove a child by index. This method
107      * fires the appropriate event in accordance with the Strucutral interface.
108      *
109      * @param index The index of the child to remove.
110      * @return The child removed.
111      */

112     public Object JavaDoc removeChildAt(int index) {
113         removeStateListenerAt(index);
114         return super.removeChildAt(index);
115     }
116
117     private void removeStateListener(Object JavaDoc child) {
118         synchronized (jobStates) {
119             if (child instanceof Stateful) {
120                 ChildStateListener l = (ChildStateListener) listeners.remove(child);
121                 ((Stateful) child).removeJobStateListener(l);
122                 jobStates.remove(child);
123             }
124         }
125     }
126     
127     /**
128      * Remove a child. This method
129      * fires the appropriate event in accordance with the Strucutral interface.
130      *
131      * @param child The child to remove.
132      */

133     public void removeChild(Object JavaDoc child) {
134         removeStateListener(child);
135         super.removeChild(child);
136     }
137         
138     public void softResetChildren() {
139         if (jobStates.size() > 0) {
140             super.softResetChildren();
141         }
142         else {
143             stateHandler.setJobStateReady();
144         }
145     }
146     
147     public void hardResetChildren() {
148         if (jobStates.size() > 0) {
149             super.hardResetChildren();
150         }
151         else {
152             stateHandler.setJobStateReady();
153         }
154     }
155     
156     /**
157      * Check any child exceptions.
158      *
159      * @return An OddjobChildException if any jobs are in an excpetion state.
160      * null otherwise.
161      */

162
163     public OddjobChildException anyExceptions() {
164         synchronized (jobStates) {
165             for (Iterator JavaDoc it = jobStates.entrySet().iterator(); it.hasNext(); ) {
166                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
167                 JobStateEvent event = (JobStateEvent) entry.getValue();
168                 if (event.getJobState() == JobState.EXCEPTION) {
169                     return new OddjobChildException("Exception in child [" + entry.getKey() + "]",
170                             event.getException());
171                 }
172             }
173         }
174         return null;
175     }
176     
177     /**
178      * Utility method to check if any jobs are not complete.
179      *
180      * @return true if any jobs are not complete.
181      */

182     public boolean anyNotComplete() {
183         synchronized (jobStates) {
184             for (Iterator JavaDoc it = jobStates.entrySet().iterator(); it.hasNext(); ) {
185                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
186                 JobStateEvent event = (JobStateEvent) entry.getValue();
187                 if (event.getJobState() == JobState.NOT_COMPLETE) {
188                     return true;
189                 }
190             }
191         }
192         return false;
193     }
194
195     /**
196      * Utility method to check all jobs are complete.
197      *
198      * @return true if all jobs are complete.
199      */

200     public boolean allComplete() {
201         synchronized (jobStates) {
202             for (Iterator JavaDoc it = jobStates.entrySet().iterator(); it.hasNext(); ) {
203                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
204                 JobStateEvent event = (JobStateEvent) entry.getValue();
205                 if (event.getJobState() != JobState.COMPLETE) {
206                     return false;
207                 }
208             }
209         }
210         return true;
211     }
212
213     /**
214      * Utility method to check all jobs are ready.
215      *
216      * @return true if all jobs are ready.
217      */

218     public boolean anyReady() {
219         synchronized (jobStates) {
220             for (Iterator JavaDoc it = jobStates.entrySet().iterator(); it.hasNext(); ) {
221                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
222                 JobStateEvent event = (JobStateEvent) entry.getValue();
223                 if (event.getJobState() == JobState.READY) {
224                     return true;
225                 }
226             }
227         }
228         return false;
229     }
230     
231     public void refreshState() {
232         // a job with no children must be ready otherwise
233
// Oddjob would never be ready when it was reset.
234
if (size() == 0) {
235             stateHandler.setJobStateReady();
236             return;
237         }
238         
239         Exception JavaDoc e = anyExceptions();
240         if (e != null) {
241             stateHandler.setJobStateException(e);
242         }
243         else if (anyNotComplete()) {
244             stateHandler.setJobStateNotComplete();
245         }
246         else if (allComplete()) {
247             stateHandler.setJobStateComplete();
248         }
249         else if (anyReady()) {
250             stateHandler.setJobStateReady();
251         }
252     }
253     
254     public void destroyAll() {
255         super.destroyAll();
256         // If a job destroys its' children it should then be ready.
257
// i.e. Oddjob.
258
refreshState();
259         initialised = false;
260     }
261     
262     /**
263      * Listen to child states.
264      *
265      */

266     public class ChildStateListener implements JobStateListener {
267         /** The identifier in the jobStates map. */
268         final Object JavaDoc key;
269         
270         public ChildStateListener(Object JavaDoc key) {
271             if (key == null) {
272                 throw new NullPointerException JavaDoc("Child key can't be null!");
273             }
274             this.key = key;
275         }
276         
277         public void jobStateChange(JobStateEvent event) {
278             synchronized (jobStates) {
279                 if (event == null) {
280                     throw new NullPointerException JavaDoc("Event can't be null!");
281                 }
282                 jobStates.put(key, event);
283                 if (!initialised) {
284                     return;
285                 }
286                 refreshState();
287             }
288         }
289     }
290
291     /**
292      * Add a job state listener.
293      */

294     public void addJobStateListener(JobStateListener listener) {
295         stateHandler.addJobStateListener(listener);
296     }
297
298     /**
299      * Remove a job state listener.
300      */

301     public void removeJobStateListener(JobStateListener listener){
302         stateHandler.removeJobStateListener(listener);
303     }
304     
305     public void dump(PrintStream JavaDoc out) {
306         for (Iterator JavaDoc it = jobStates.entrySet().iterator(); it.hasNext(); ) {
307             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
308             JobStateEvent event = (JobStateEvent) entry.getValue();
309             out.println(entry.getKey() + "=" + event);
310         }
311
312     }
313     
314 }
315
Popular Tags