KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > prefuse > activity > ActivityManager


1 package prefuse.activity;
2
3 import java.util.ArrayList JavaDoc;
4
5 import prefuse.util.PrefuseConfig;
6
7
8 /**
9  * <p>The ActivityManager is responsible for scheduling and running timed
10  * activities that perform data processing and animation.</p>
11  *
12  * <p>The AcivityManager runs in its own separate thread of execution, and
13  * one instance is used to schedule activities from any number of currently
14  * active visualizations. The class is implemented as a singleton; the single
15  * instance of this class is interacted with through static methods. These
16  * methods are called by an Activity's run methods, and so are made only
17  * package visible here.</p>
18  *
19  * <p>Activity instances can be scheduled by using their
20  * {@link prefuse.activity.Activity#run()},
21  * {@link prefuse.activity.Activity#runAt(long)}, and
22  * {@link prefuse.activity.Activity#runAfter(Activity)}
23  * methods. These will automatically call the
24  * appropriate methods with the ActivityManager.</p>
25  *
26  * <p>For {@link prefuse.action.Action} instances, one can also register
27  * the actions with a {@link prefuse.Visualization} and use the
28  * visualizations provided run methods to launch Actions in a
29  * convenient fashion. The interface, which is backed by an {@link ActivityMap}
30  * instance, also provides a useful level of indirection, allowing actions
31  * to be changed dynamically without changes to code in other locations.
32  * </p>
33  *
34  * @author <a HREF="http://jheer.org">jeffrey heer</a>
35  * @see Activity
36  * @see prefuse.action.Action
37  */

38 public class ActivityManager extends Thread JavaDoc {
39     
40     private static ActivityManager s_instance;
41     
42     private ArrayList JavaDoc m_activities;
43     private ArrayList JavaDoc m_tmp;
44     private long m_nextTime;
45     private boolean m_run;
46     
47     /**
48      * Returns the active ActivityManager instance.
49      * @return the ActivityManager
50      */

51     private synchronized static ActivityManager getInstance() {
52         if ( s_instance == null || !s_instance.isAlive() ) {
53             s_instance = new ActivityManager();
54         }
55         return s_instance;
56     }
57     
58     /**
59      * Create a new ActivityManger.
60      */

61     private ActivityManager() {
62         super("prefuse_ActivityManager");
63         m_activities = new ArrayList JavaDoc();
64         m_tmp = new ArrayList JavaDoc();
65         m_nextTime = Long.MAX_VALUE;
66         
67         int priority = PrefuseConfig.getInt("activity.threadPriority");
68         if ( priority >= Thread.MIN_PRIORITY &&
69              priority <= Thread.MAX_PRIORITY )
70         {
71             this.setPriority(priority);
72         }
73         this.setDaemon(true);
74         this.start();
75     }
76     
77     /**
78      * Stops the activity manager thread. All scheduled actvities are
79      * canceled, and then the thread is then notified to stop running.
80      */

81     public static void stopThread() {
82         ActivityManager am;
83         synchronized ( ActivityManager.class ) {
84             am = s_instance;
85         }
86         if ( am != null )
87             am._stop();
88     }
89     
90     /**
91      * Schedules an Activity with the manager.
92      * @param a the Activity to schedule
93      */

94     static void schedule(Activity a) {
95         getInstance()._schedule(a, a.getStartTime());
96     }
97     
98     /**
99      * Schedules an Activity to start immediately, overwriting the
100      * Activity's currently set startTime.
101      * @param a the Activity to schedule
102      */

103     static void scheduleNow(Activity a) {
104         getInstance()._schedule(a, System.currentTimeMillis());
105     }
106     
107     /**
108      * Schedules an Activity at the specified startTime, overwriting the
109      * Activity's currently set startTime.
110      * @param a the Activity to schedule
111      * @param startTime the time at which the activity should run
112      */

113     static void scheduleAt(Activity a, long startTime) {
114         getInstance()._schedule(a, startTime);
115     }
116     
117     /**
118      * Schedules an Activity to start immediately after another Activity.
119      * The second Activity will be scheduled to start immediately after the
120      * first one finishes, overwriting any previously set startTime. If the
121      * first Activity is cancelled, the second one will not run.
122      *
123      * This functionality is provided by using an ActivityListener to monitor
124      * the first Activity. The listener is removed upon completion or
125      * cancellation of the first Activity.
126      *
127      * This method does not effect the scheduling of the first Activity.
128      * @param before the first Activity to run
129      * @param after the Activity to run immediately after the first
130      */

131     static void scheduleAfter(Activity before, Activity after) {
132         getInstance()._scheduleAfter(before, after);
133     }
134     
135     /**
136      * Schedules an Activity to start immediately after another Activity.
137      * The second Activity will be scheduled to start immediately after the
138      * first one finishes, overwriting any previously set startTime. If the
139      * first Activity is cancelled, the second one will not run.
140      *
141      * This functionality is provided by using an ActivityListener to monitor
142      * the first Activity. The listener will persist across mulitple runs,
143      * meaning the second Activity will always be evoked upon a successful
144      * finish of the first.
145      *
146      * This method does not otherwise effect the scheduling of the first Activity.
147      * @param before the first Activity to run
148      * @param after the Activity to run immediately after the first
149      */

150     static void alwaysScheduleAfter(Activity before, Activity after) {
151         getInstance()._alwaysScheduleAfter(before, after);
152     }
153     
154     /**
155      * Removes an Activity from this manager, called by an
156      * Activity when it finishes or is cancelled. Application
157      * code should not call this method! Instead, use
158      * Activity.cancel() to stop a sheduled or running Activity.
159      * @param a
160      * @return true if the activity was found and removed, false
161      * if the activity is not scheduled with this manager.
162      */

163     static void removeActivity(Activity a) {
164         getInstance()._removeActivity(a);
165     }
166     
167     /**
168      * Returns the number of scheduled activities
169      * @return the number of scheduled activities
170      */

171     public static int activityCount() {
172         return getInstance()._activityCount();
173     }
174     
175     /**
176      * Stops the activity manager thread. All scheduled actvities are
177      * canceled, and then the thread is then notified to stop running.
178      */

179     private synchronized void _stop() {
180         while ( m_activities.size() > 0 ) {
181             Activity a = (Activity)m_activities.get(m_activities.size()-1);
182             a.cancel();
183         }
184         _setRunning(false);
185         notify();
186     }
187     
188     /**
189      * Schedules an Activity with the manager.
190      * @param a the Activity to schedule
191      */

192     private void _schedule(Activity a, long startTime) {
193         if ( a.isScheduled() ) {
194             return; // already scheduled, do nothing
195
}
196         a.setStartTime(startTime);
197         synchronized ( this ) {
198             m_activities.add(a);
199             a.setScheduled(true);
200             if ( startTime < m_nextTime ) {
201                m_nextTime = startTime;
202                notify();
203             }
204         }
205     }
206     
207     /**
208      * Schedules an Activity to start immediately after another Activity.
209      * The second Activity will be scheduled to start immediately after the
210      * first one finishes, overwriting any previously set startTime. If the
211      * first Activity is cancelled, the second one will not run.
212      *
213      * This functionality is provided by using an ActivityListener to monitor
214      * the first Activity. The listener is removed upon completion or
215      * cancellation of the first Activity.
216      *
217      * This method does not effect the scheduling of the first Activity.
218      * @param before the first Activity to run
219      * @param after the Activity to run immediately after the first
220      */

221     private void _scheduleAfter(Activity before, Activity after) {
222         before.addActivityListener(new ScheduleAfterActivity(after,true));
223     }
224     
225     /**
226      * Schedules an Activity to start immediately after another Activity.
227      * The second Activity will be scheduled to start immediately after the
228      * first one finishes, overwriting any previously set startTime. If the
229      * first Activity is cancelled, the second one will not run.
230      *
231      * This functionality is provided by using an ActivityListener to monitor
232      * the first Activity. The listener will persist across mulitple runs,
233      * meaning the second Activity will always be evoked upon a successful
234      * finish of the first.
235      *
236      * This method does not otherwise effect the scheduling of the first Activity.
237      * @param before the first Activity to run
238      * @param after the Activity to run immediately after the first
239      */

240     private void _alwaysScheduleAfter(Activity before, Activity after) {
241         before.addActivityListener(new ScheduleAfterActivity(after,false));
242     }
243     
244     /**
245      * Removes an Activity from this manager, called by an
246      * Activity when it finishes or is cancelled. Application
247      * code should not call this method! Instead, use
248      * Activity.cancel() to stop a sheduled or running Activity.
249      * @param a
250      * @return true if the activity was found and removed, false
251      * if the activity is not scheduled with this manager.
252      */

253     private boolean _removeActivity(Activity a) {
254         boolean r;
255         synchronized ( this ) {
256             r = m_activities.remove(a);
257             if ( r ) {
258                 if ( m_activities.size() == 0 ) {
259                     m_nextTime = Long.MAX_VALUE;
260                 }
261             }
262         }
263         if ( r ) {
264             a.setScheduled(false);
265         }
266         return r;
267     }
268     
269     /**
270      * Returns the number of scheduled activities
271      * @return the number of scheduled activities
272      */

273     private synchronized int _activityCount() {
274         return m_activities.size();
275     }
276     
277     /**
278      * Sets the running flag for the ActivityManager instance.
279      */

280     private synchronized void _setRunning(boolean b) {
281         m_run = b;
282     }
283     
284     /**
285      * Used by the activity loop to determine if the ActivityManager
286      * thread should keep running or exit.
287      */

288     private synchronized boolean _keepRunning() {
289         return m_run;
290     }
291     
292     /**
293      * Main scheduling thread loop. This is automatically started upon
294      * initialization of the ActivityManager.
295      */

296     public void run() {
297         _setRunning(true);
298         while ( _keepRunning() ) {
299             if ( _activityCount() > 0 ) {
300                 long currentTime = System.currentTimeMillis();
301                 long t = -1;
302                 
303                 synchronized (this) {
304                     // copy content of activities, as new activities might
305
// be added while we process the current ones
306
for ( int i=0; i<m_activities.size(); i++ ) {
307                         Activity a = (Activity)m_activities.get(i);
308                         m_tmp.add(a);
309                         
310                         // remove activities that won't be run again
311
if ( currentTime >= a.getStopTime() )
312                         {
313                             m_activities.remove(i--);
314                             a.setScheduled(false);
315                         }
316                     }
317                     // if no activities left, reflect that in the next time
318
if ( m_activities.size() == 0 ) {
319                         m_nextTime = Long.MAX_VALUE;
320                     }
321                 }
322                 
323                 for ( int i=0; i<m_tmp.size(); i++ ) {
324                     // run the activity - the activity will check for
325
// itself if it should perform any action or not
326
Activity a = (Activity)m_tmp.get(i);
327                     long s = a.runActivity(currentTime);
328                     // compute minimum time for next activity cycle
329
t = (s<0 ? t : t<0 ? s : Math.min(t,s));
330                 }
331
332                 // clear the temporary list
333
m_tmp.clear();
334                 
335                 if ( t == -1 ) continue;
336