KickJava   Java API By Example, From Geeks To Geeks.

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


1 package org.oddjob.structural;
2
3 import java.util.ArrayList JavaDoc;
4 import java.util.Iterator JavaDoc;
5 import java.util.List JavaDoc;
6
7 import org.oddjob.Resetable;
8 import org.oddjob.Stoppable;
9 import org.oddjob.Structural;
10 import org.oddjob.arooa.Lifecycle;
11
12 /**
13  * Helper for managing child Objects. This class will track structural
14  * changes and notify listeners.
15  *
16  * @author Rob Gordon
17  */

18
19 public class ChildHelper {
20
21     /** Contains the child jobs. */
22     private final List JavaDoc jobList = new ArrayList JavaDoc();
23     
24     /** Structural listeners. */
25     private final List JavaDoc listeners = new ArrayList JavaDoc();
26     
27     private final Object JavaDoc source;
28     
29     /**
30      * Constructor.
31      *
32      * @param source The source used as the source of the event.
33      */

34     public ChildHelper(Object JavaDoc source) {
35         this.source = source;
36     }
37     /**
38      * Add a child. This method
39      * fires the appropriate event in accordance with the structural interface.
40      *
41      * @param child A child object.
42      */

43     public void addChild(Object JavaDoc child) {
44         if (child == null) {
45             throw new NullPointerException JavaDoc("Attempt to add a null child.");
46         }
47
48         int newIndex = 0;
49         synchronized (jobList) {
50             newIndex = jobList.size();
51             jobList.add(child);
52         }
53         StructuralEvent event = new StructuralEvent(source, child, newIndex);
54         notifyChildAdded(event);
55     }
56
57     /**
58      * Insert a child.
59      *
60      * @param index The index.
61      * @param child The child.
62      */

63     public void insertChild(int index, Object JavaDoc child) {
64         if (child == null) {
65             throw new NullPointerException JavaDoc("Attempt to add a null child.");
66         }
67
68         synchronized (jobList) {
69             jobList.add(index, child);
70         }
71         StructuralEvent event = new StructuralEvent(source, child, index);
72         notifyChildAdded(event);
73     }
74
75     /**
76      * Add an array of children.
77      *
78      * @param children The children.
79      */

80     public void addChildren(Object JavaDoc[] children) {
81         for (int i = 0; i < children.length; ++i) {
82             addChild(children[i]);
83         }
84     }
85     
86     /**
87      * Remove a child by index. This method
88      * fires the appropriate event in accordance with the Strucutral interface.
89      *
90      * @param index The index of the child to remove.
91      * @return The child removed.
92      */

93     public Object JavaDoc removeChildAt(int index) {
94         Object JavaDoc child = null;
95         
96         synchronized (jobList) {
97             child = jobList.remove(index);
98         }
99         StructuralEvent event = new StructuralEvent(source, child, index);
100         
101         notifyChildRemoved(event);
102         return child;
103     }
104
105     /**
106      * Remove a child. This method
107      * fires the appropriate event in accordance with the Strucutral interface.
108      *
109      * @param child The child to remove.
110      */

111     public void removeChild(Object JavaDoc child) {
112         int oldIndex = 0;
113         
114         synchronized (jobList) {
115             oldIndex = jobList.indexOf(child);
116             if (oldIndex == -1) {
117                 return;
118             }
119             jobList.remove(oldIndex);
120         }
121         StructuralEvent event = new StructuralEvent(source, child, oldIndex);
122         notifyChildRemoved(event);
123     }
124     
125     /**
126      * Replace a child. This method
127      * fires the appropriate event in accordance with the Strucutral interface.
128      *
129      * @param child The child to remove.
130      * @param replacement The child to replace.
131      */

132     public void replaceChild(Object JavaDoc child, Object JavaDoc replacement) {
133         int oldIndex = 0;
134         
135         synchronized (jobList) {
136             oldIndex = jobList.indexOf(child);
137             if (oldIndex == -1) {
138                 return;
139             }
140             removeChildAt(oldIndex);
141             insertChild(oldIndex, replacement);
142         }
143     }
144     
145     /**
146      * Allows a sub class to remove all children from itself. This method
147      * fires the appropriate events in accordance with the structural interface.
148      * <p>
149      * This meothod doesn't destroy children. It may be more appropriate
150      * to use destroyAll.
151      */

152     public void removeAllChildren() {
153         while (true) {
154             int size = jobList.size();
155             if (size == 0) {
156                 break;
157             }
158             removeChildAt(size - 1);
159         }
160     }
161
162     /**
163      * Stop all the child jobs. This is a convienicne method that sub classes
164      * can choose to use if required.
165      */

166     public void stopChildren() {
167         Object JavaDoc [] children = getChildren();
168         for (int i = 0; i < children.length; ++i) {
169             if (children[i] instanceof Stoppable) {
170                 ((Stoppable)children[i]).stop();
171             }
172         }
173     }
174
175     /**
176      * Perform a soft reset. This method propergates the soft reset message down to
177      * all child jobs. This is a convenience method that a sub class can choose to use.
178      */

179     public void softResetChildren() {
180         Object JavaDoc [] children = getChildren();
181         for (int i = 0; i < children.length; ++i) {
182             if (children[i] instanceof Resetable) {
183                 ((Resetable)children[i]).softReset();
184             }
185         }
186     }
187
188     /**
189      * Perform a hard reset. This method propergates the hard reset message down
190      * to all child jobs. This is a convenience method a sub class can choose to use.
191      */

192     public void hardResetChildren() {
193         Object JavaDoc [] children = getChildren();
194         for (int i = 0; i < children.length; ++i) {
195             if (children[i] instanceof Resetable) {
196                 ((Resetable)children[i]).hardReset();
197             }
198         }
199     }
200
201     /**
202      * Return an array of children.
203      *
204      * @return An array of child objects.
205      */

206     public Object JavaDoc[] getChildren() {
207         synchronized (jobList) {
208             return jobList.toArray();
209         }
210     }
211     
212     /**
213      * Return a child.
214      *
215      * @return A child.
216      */

217     public Object JavaDoc getChildAt(int index) {
218         synchronized (jobList) {
219             return jobList.get(index);
220         }
221     }
222     
223     /**
224      * Return an only child.
225      *
226      * @return A child.
227      */

228     public Object JavaDoc getChild() {
229         synchronized (jobList) {
230             if (jobList.size() == 0) {
231                 return null;
232             }
233             if (jobList.size() > 1) {
234                 throw new IllegalStateException JavaDoc("Can't use getChild with more than one child!");
235             }
236             return jobList.get(0);
237         }
238     }
239     
240     /*
241      * (non-Javadoc)
242      * @see org.oddjob.structural.Structural#addStructuralListener(org.oddjob.structural.StructuralListener)
243      */

244     public void addStructuralListener(StructuralListener listener) {
245         // could this cause deadlock? possibly be we must garantee that a listener
246
// doesn't miss an event.
247
synchronized (listeners) {
248             Object JavaDoc [] children = getChildren();
249             for (int i = 0; i < children.length; ++i) {
250                 StructuralEvent event = new StructuralEvent(source, children[i], i);
251                 listener.childAdded(event);
252             }
253             listeners.add(listener);
254         }
255     }
256     
257     /*
258      * (non-Javadoc)
259      * @see org.oddjob.structural.Structural#removeStructuralListener(org.oddjob.structural.StructuralListener)
260      */

261     public void removeStructuralListener(StructuralListener listener) {
262         synchronized (listeners) {
263             listeners.remove(listener);
264         }
265     }
266     
267     /**
268      * The number of children.
269      *
270      * @return The number of children.
271      */

272     public int size() {
273         synchronized (jobList) {
274             return jobList.size();
275         }
276     }
277     
278     /**
279      * Notify the listeners.
280      *
281      * @param event The event.
282      */

283     private void notifyChildAdded(StructuralEvent event) {
284         List JavaDoc copy = null;
285         synchronized (listeners) {
286             copy = new ArrayList JavaDoc(listeners);
287         }
288         for (Iterator JavaDoc it = copy.iterator(); it.hasNext() ;) {
289             ((StructuralListener)it.next()).childAdded(event);
290         }
291     }
292     
293     /*
294      * Notify the listeners.
295      *
296      * @param event The event.
297      */

298     private void notifyChildRemoved(StructuralEvent event) {
299         List JavaDoc copy = null;
300         synchronized (listeners) {
301             copy = new ArrayList JavaDoc(listeners);
302         }
303         for (Iterator JavaDoc it = copy.iterator(); it.hasNext() ;) {
304             ((StructuralListener)it.next()).childRemoved(event);
305         }
306     }
307     
308     /**
309      * Destroy all the children and remove them.
310      *
311      */

312     public void destroyAll() {
313         // order is important here - destroy first so notifications
314
// are from the bottom up.
315
Lifecycle.destroy(getChildren());
316         removeAllChildren();
317     }
318     
319     public static Object JavaDoc[] getChildren(Structural structural) {
320         class ChildCatcher implements StructuralListener {
321             List JavaDoc results = new ArrayList JavaDoc();
322             public void childAdded(StructuralEvent event) {
323                 synchronized (results) {
324                     results.add(event.getIndex(), event.getChild());
325                 }
326             }
327             public void childRemoved(StructuralEvent event) {
328                 synchronized (results) {
329                     results.remove(event.getIndex());
330                 }
331             }
332         }
333         ChildCatcher cc = new ChildCatcher();
334         structural.addStructuralListener(cc);
335         structural.removeStructuralListener(cc);
336         return cc.results.toArray();
337     }
338 }
339
Popular Tags