EMMA Coverage Report (generated Wed Oct 03 05:00:03 CEST 2012)
[all classes][org.jdtaus.core.monitor.ri]

COVERAGE SUMMARY FOR SOURCE FILE [DefaultTaskMonitor.java]

nameclass, %method, %block, %line, %
DefaultTaskMonitor.java100% (3/3)88%  (22/25)71%  (470/664)75%  (109.2/145)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class DefaultTaskMonitor100% (1/1)85%  (17/20)68%  (396/581)73%  (90.2/123)
DefaultTaskMonitor (long): void 0%   (0/1)0%   (0/24)0%   (0/6)
getTaskAlreadyStartedMessage (Locale, String, Date): String 0%   (0/1)0%   (0/16)0%   (0/1)
getThreadDiedMessage (Locale): String 0%   (0/1)0%   (0/7)0%   (0/1)
removeTaskListener (TaskListener): void 100% (1/1)35%  (7/20)50%  (2/4)
checkMonitorThread (): void 100% (1/1)51%  (20/39)62%  (5/8)
removeTaskState (Task): void 100% (1/1)62%  (8/13)75%  (3/4)
getTaskListeners (): TaskListener [] 100% (1/1)64%  (9/14)64%  (0.6/1)
changedState (Task): boolean 100% (1/1)68%  (106/157)64%  (27/42)
fireTaskEvent (TaskEvent): void 100% (1/1)71%  (41/58)72%  (7.2/10)
createTaskState (Task): void 100% (1/1)76%  (58/76)93%  (14/15)
monitor (Task): void 100% (1/1)85%  (28/33)98%  (7.8/8)
finish (Task): void 100% (1/1)88%  (37/42)97%  (8.7/9)
DefaultTaskMonitor (): void 100% (1/1)100% (14/14)100% (4/4)
addTaskListener (TaskListener): void 100% (1/1)100% (20/20)100% (4/4)
getDefaultPollIntervalMillis (): Long 100% (1/1)100% (6/6)100% (1/1)
getLocale (): Locale 100% (1/1)100% (6/6)100% (1/1)
getLogger (): Logger 100% (1/1)100% (6/6)100% (1/1)
getPollIntervalMillis (): long 100% (1/1)100% (11/11)100% (3/3)
getTaskListener (): TaskListener [] 100% (1/1)100% (7/7)100% (1/1)
getThreadStartedMessage (Locale, Number): String 100% (1/1)100% (12/12)100% (1/1)
     
class DefaultTaskMonitor$MonitorThread100% (1/1)100% (4/4)89%  (71/80)86%  (18/21)
run (): void 100% (1/1)60%  (6/10)52%  (2.6/5)
checkTasks (): void 100% (1/1)88%  (37/42)93%  (8.4/9)
DefaultTaskMonitor$MonitorThread (DefaultTaskMonitor, long): void 100% (1/1)100% (10/10)100% (4/4)
start (): void 100% (1/1)100% (18/18)100% (3/3)
     
class DefaultTaskMonitor$TaskState100% (1/1)100% (1/1)100% (3/3)100% (1/1)
DefaultTaskMonitor$TaskState (): void 100% (1/1)100% (3/3)100% (1/1)

1/*
2 *  jDTAUS Core RI Task Monitor
3 *  Copyright (C) 2005 Christian Schulte
4 *  <cs@schulte.it>
5 *
6 *  This library is free software; you can redistribute it and/or
7 *  modify it under the terms of the GNU Lesser General Public
8 *  License as published by the Free Software Foundation; either
9 *  version 2.1 of the License, or any later version.
10 *
11 *  This library is distributed in the hope that it will be useful,
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 *  Lesser General Public License for more details.
15 *
16 *  You should have received a copy of the GNU Lesser General Public
17 *  License along with this library; if not, write to the Free Software
18 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19 *
20 */
21package org.jdtaus.core.monitor.ri;
22 
23import java.util.Date;
24import java.util.HashMap;
25import java.util.Iterator;
26import java.util.Locale;
27import java.util.Map;
28import javax.swing.event.EventListenerList;
29import org.jdtaus.core.container.ContainerFactory;
30import org.jdtaus.core.logging.spi.Logger;
31import org.jdtaus.core.monitor.Task;
32import org.jdtaus.core.monitor.TaskEvent;
33import org.jdtaus.core.monitor.TaskListener;
34import org.jdtaus.core.monitor.spi.TaskMonitor;
35import org.jdtaus.core.text.Message;
36 
37/**
38 * jDTAUS Core SPI {@code TaskMonitor} reference implementation.
39 * <p>The reference implementation uses a thread checking the state of all tasks
40 * in the system periodically which is started upon initialization and runs
41 * endlessly. Monitoring is controlled by property {@code pollIntervalMillis}
42 * specifying the milliseconds of one period. Each time a period ends, tasks
43 * are checked for state changes and corresponding events are fired. Property
44 * {@code pollIntervalMillis} defaults to {@code 250ms}.</p>
45 *
46 * <p><b>Note:</b><br/>
47 * {@code TaskEvent}s of type {@code STARTED} and {@code ENDED} are fired by the
48 * thread executing the task's operation. Since tasks are monitored
49 * asynchronously, {@code TaskEvent}s of type {@code CHANGED_STATE} are fired by
50 * the monitor thread, not by the thread executing the task's operation. Make
51 * sure {@code TaskListener} implementations are prepared for being notified
52 * by a different thread than the one executing a task's operation.</p>
53 *
54 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
55 * @version $JDTAUS: DefaultTaskMonitor.java 8641 2012-09-27 06:45:17Z schulte $
56 *
57 * @see org.jdtaus.core.container.Container
58 */
59public class DefaultTaskMonitor implements TaskMonitor
60{
61    //--Constructors------------------------------------------------------------
62 
63// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausConstructors
64    // This section is managed by jdtaus-container-mojo.
65 
66    /** Standard implementation constructor <code>org.jdtaus.core.monitor.ri.DefaultTaskMonitor</code>. */
67    public DefaultTaskMonitor()
68    {
69        super();
70    }
71 
72// </editor-fold>//GEN-END:jdtausConstructors
73 
74    //------------------------------------------------------------Constructors--
75    //--Dependencies------------------------------------------------------------
76 
77// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausDependencies
78    // This section is managed by jdtaus-container-mojo.
79 
80    /**
81     * Gets the configured <code>Logger</code> implementation.
82     *
83     * @return The configured <code>Logger</code> implementation.
84     */
85    private Logger getLogger()
86    {
87        return (Logger) ContainerFactory.getContainer().
88            getDependency( this, "Logger" );
89 
90    }
91 
92    /**
93     * Gets the configured <code>TaskListener</code> implementation.
94     *
95     * @return The configured <code>TaskListener</code> implementation.
96     */
97    private TaskListener[] getTaskListener()
98    {
99        return (TaskListener[]) ContainerFactory.getContainer().
100            getDependency( this, "TaskListener" );
101 
102    }
103 
104    /**
105     * Gets the configured <code>Locale</code> implementation.
106     *
107     * @return The configured <code>Locale</code> implementation.
108     */
109    private Locale getLocale()
110    {
111        return (Locale) ContainerFactory.getContainer().
112            getDependency( this, "Locale" );
113 
114    }
115 
116// </editor-fold>//GEN-END:jdtausDependencies
117 
118    //------------------------------------------------------------Dependencies--
119    //--Properties--------------------------------------------------------------
120 
121// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausProperties
122    // This section is managed by jdtaus-container-mojo.
123 
124    /**
125     * Gets the value of property <code>defaultPollIntervalMillis</code>.
126     *
127     * @return Default number of milliseconds per poll interval.
128     */
129    private java.lang.Long getDefaultPollIntervalMillis()
130    {
131        return (java.lang.Long) ContainerFactory.getContainer().
132            getProperty( this, "defaultPollIntervalMillis" );
133 
134    }
135 
136// </editor-fold>//GEN-END:jdtausProperties
137 
138    //--------------------------------------------------------------Properties--
139    //--TaskEventSource---------------------------------------------------------
140 
141    public void addTaskListener( final TaskListener listener )
142    {
143        if ( listener == null )
144        {
145            throw new NullPointerException( "listener" );
146        }
147 
148        this.taskListeners.add( TaskListener.class, listener );
149    }
150 
151    public void removeTaskListener( final TaskListener listener )
152    {
153        if ( listener == null )
154        {
155            throw new NullPointerException( "listener" );
156        }
157 
158        this.taskListeners.remove( TaskListener.class, listener );
159    }
160 
161    public TaskListener[] getTaskListeners()
162    {
163        return (TaskListener[]) this.taskListeners.getListeners(
164            TaskListener.class );
165 
166    }
167 
168    //---------------------------------------------------------TaskEventSource--
169    //--TaskMonitor-------------------------------------------------------------
170 
171    public void monitor( final Task task )
172    {
173        if ( task == null )
174        {
175            throw new NullPointerException( "task" );
176        }
177 
178        synchronized ( this.stateMap )
179        {
180            this.checkMonitorThread();
181            this.createTaskState( task );
182            this.fireTaskEvent( new TaskEvent( task, TaskEvent.STARTED ) );
183        }
184    }
185 
186    public void finish( final Task task )
187    {
188        if ( task == null )
189        {
190            throw new NullPointerException( "task" );
191        }
192 
193        synchronized ( this.stateMap )
194        {
195            if ( this.changedState( task ) )
196            {
197                this.fireTaskEvent( new TaskEvent( task,
198                                                   TaskEvent.CHANGED_STATE ) );
199 
200            }
201 
202            this.removeTaskState( task );
203            this.fireTaskEvent( new TaskEvent( task, TaskEvent.ENDED ) );
204        }
205    }
206 
207    //-------------------------------------------------------------TaskMonitor--
208    //--DefaultTaskMonitor------------------------------------------------------
209 
210    /** List of {@code TaskListener}s. */
211    private final EventListenerList taskListeners = new EventListenerList();
212 
213    /** The thread monitoring tasks. */
214    private MonitorThread monitorThread;
215 
216    /** Maps {@code Task}s to corresponding {@code TaskState} instances. */
217    private final Map stateMap = new HashMap( 1000 );
218 
219    /** Number of milliseconds per poll interval. */
220    private Long pollIntervalMillis;
221 
222    /**
223     * Creates a new {@code DefaultTaskMonitor} instance taking the
224     * milliseconds of one period.
225     *
226     * @param pollIntervalMillis the number of milliseconds per poll interval.
227     */
228    public DefaultTaskMonitor( final long pollIntervalMillis )
229    {
230        if ( pollIntervalMillis > 0L )
231        {
232            this.pollIntervalMillis = new Long( pollIntervalMillis );
233        }
234    }
235 
236    /**
237     * Gets the value of property {@code pollIntervalMillis}.
238     *
239     * @return the number of milliseconds per poll interval.
240     */
241    private long getPollIntervalMillis()
242    {
243        if ( this.pollIntervalMillis == null )
244        {
245            this.pollIntervalMillis = this.getDefaultPollIntervalMillis();
246        }
247 
248        return this.pollIntervalMillis.longValue();
249    }
250 
251    /** Caches the state of a task. */
252    private static final class TaskState
253    {
254 
255        boolean indeterminate;
256 
257        boolean cancelable;
258 
259        boolean cancelled;
260 
261        int minimum;
262 
263        int maximum;
264 
265        int progress;
266 
267        Message progressDescription;
268 
269    }
270 
271    /** Thread monitoring all currently running {@code Task}s for changes. */
272    private class MonitorThread extends Thread
273    {
274 
275        /** Milliseconds per poll interval. */
276        private final long pollIntervalMillis;
277 
278        /** Creates a new {@code MonitorThread} instance. */
279        private MonitorThread( final long pollIntervalMillis )
280        {
281            super( "DefaultTaskMonitor" );
282            this.pollIntervalMillis = pollIntervalMillis;
283        }
284 
285        /** {@inheritDoc} */
286        public void run()
287        {
288            while ( true )
289            {
290                try
291                {
292                    Thread.sleep( this.pollIntervalMillis );
293                    this.checkTasks();
294                }
295                catch ( InterruptedException e )
296                {
297                    this.checkTasks();
298                }
299            }
300        }
301 
302        public void start()
303        {
304            super.start();
305            getLogger().debug( getThreadStartedMessage(
306                getLocale(), new Long( this.pollIntervalMillis ) ) );
307 
308        }
309 
310        /**
311         * Checks the state of all currently running tasks for changes and
312         * fires corresponding events.
313         */
314        private void checkTasks()
315        {
316            synchronized ( DefaultTaskMonitor.this.stateMap )
317            {
318                for ( Iterator it = DefaultTaskMonitor.this.stateMap.keySet().
319                    iterator(); it.hasNext(); )
320                {
321                    final Task task = (Task) it.next();
322                    if ( changedState( task ) )
323                    {
324                        fireTaskEvent( new TaskEvent(
325                            task, TaskEvent.CHANGED_STATE ) );
326 
327                    }
328                }
329            }
330        }
331 
332    }
333 
334    /**
335     * Gets the monitor thread.
336     *
337     * @return the monitor thread.
338     */
339    private synchronized void checkMonitorThread()
340    {
341        if ( this.monitorThread == null )
342        {
343            this.monitorThread =
344            new MonitorThread( this.getPollIntervalMillis() );
345 
346            this.monitorThread.start();
347        }
348 
349        if ( !this.monitorThread.isAlive() )
350        { // Monitoring died for some reason; start a new thread.
351            this.getLogger().warn( this.getThreadDiedMessage(
352                this.getLocale() ) );
353 
354            this.monitorThread =
355            new MonitorThread( this.getPollIntervalMillis() );
356 
357            this.monitorThread.start();
358        }
359    }
360 
361    /**
362     * Notifies all registered {@code TaskListener}s about {@code TaskEvent}s.
363     *
364     * @param e The event to be provided to the listeners.
365     */
366    private void fireTaskEvent( final TaskEvent e )
367    {
368        if ( e == null )
369        {
370            throw new NullPointerException( "e" );
371        }
372 
373 
374        final Object[] listeners = this.taskListeners.getListenerList();
375        for ( int i = listeners.length - 2; i >= 0; i -= 2 )
376        {
377            if ( listeners[i] == TaskListener.class )
378            {
379                ( (TaskListener) listeners[i + 1] ).onTaskEvent( e );
380            }
381        }
382 
383        final TaskListener[] taskListener = this.getTaskListener();
384        for ( int i = taskListener.length - 1; i >= 0; i-- )
385        {
386            taskListener[i].onTaskEvent( e );
387        }
388    }
389 
390    /**
391     * Caches the state of a {@code Task}.
392     *
393     * @param task the task to cache state for.
394     *
395     * @throws NullPointerException if {@code task} is {@code null}.
396     * @throws IllegalStateException if the cache already holds state for
397     * {@code task}.
398     */
399    private void createTaskState( final Task task )
400    {
401        final TaskState state = new TaskState();
402        state.cancelable = task.isCancelable();
403        state.indeterminate = task.isIndeterminate();
404        state.cancelled = state.cancelable
405                          ? task.isCancelled()
406                          : false;
407 
408        state.progressDescription = task.getProgressDescription();
409 
410        if ( state.indeterminate )
411        {
412            state.maximum = Integer.MIN_VALUE;
413            state.minimum = Integer.MIN_VALUE;
414            state.progress = Integer.MIN_VALUE;
415        }
416        else
417        {
418            state.maximum = task.getMaximum();
419            state.minimum = task.getMinimum();
420            state.progress = task.getProgress();
421        }
422 
423        if ( this.stateMap.put( task, state ) != null )
424        {
425            throw new IllegalStateException( this.getTaskAlreadyStartedMessage(
426                this.getLocale(),
427                task.getDescription().getText( this.getLocale() ),
428                new Date( task.getTimestamp() ) ) );
429 
430        }
431    }
432 
433    /**
434     * Removes the cached state of a {@code Task}.
435     *
436     * @param task the task to remove the cached state of.
437     *
438     * @throws NullPointerException if {@code task} is {@code null}.
439     */
440    private void removeTaskState( final Task task )
441    {
442        if ( task == null )
443        {
444            throw new NullPointerException( "task" );
445        }
446 
447        this.stateMap.remove( task );
448    }
449 
450    /**
451     * Checks the state of a given task for changes.
452     *
453     * @param task the task to check for state changes.
454     *
455     * @return {@code true} if the state of {@code task} changed since the last
456     * time this method got called; {@code false} if the state did not change.
457     *
458     * @throws NullPointerException if {@code task} is {@code null}.
459     * @throws IllegalStateException if no cached state exists for {@code task}.
460     */
461    private boolean changedState( final Task task )
462    {
463        if ( task == null )
464        {
465            throw new NullPointerException( "task" );
466        }
467 
468 
469        boolean changedState = false;
470        final TaskState state = (TaskState) this.stateMap.get( task );
471 
472        if ( state == null )
473        {
474            throw new IllegalStateException();
475        }
476 
477        if ( state.indeterminate )
478        {
479            state.indeterminate = task.isIndeterminate();
480            if ( !state.indeterminate )
481            {
482                state.minimum = task.getMinimum();
483                state.maximum = task.getMaximum();
484                state.progress = task.getProgress();
485                changedState = true;
486            }
487        }
488        else
489        {
490            state.indeterminate = task.isIndeterminate();
491            if ( state.indeterminate )
492            {
493                changedState = true;
494            }
495            else
496            {
497                if ( state.minimum != task.getMinimum() )
498                {
499                    state.minimum = task.getMinimum();
500                    changedState = true;
501                }
502                if ( state.maximum != task.getMaximum() )
503                {
504                    state.maximum = task.getMaximum();
505                    changedState = true;
506                }
507                if ( state.progress != task.getProgress() )
508                {
509                    state.progress = task.getProgress();
510                    changedState = true;
511                }
512            }
513        }
514 
515        if ( state.cancelable )
516        {
517            state.cancelable = task.isCancelable();
518            if ( !state.cancelable )
519            {
520                changedState = true;
521            }
522            else
523            {
524                if ( state.cancelled != task.isCancelled() )
525                {
526                    state.cancelled = task.isCancelled();
527                    changedState = true;
528                }
529            }
530        }
531        else
532        {
533            state.cancelable = task.isCancelable();
534            if ( !state.cancelable )
535            {
536                state.cancelled = false;
537                changedState = true;
538            }
539        }
540 
541        if ( state.progressDescription != task.getProgressDescription() )
542        {
543            state.progressDescription = task.getProgressDescription();
544            changedState = true;
545        }
546        else if ( state.progressDescription != null &&
547                  !state.progressDescription.getText( this.getLocale() ).
548            equals( task.getProgressDescription().getText(
549            this.getLocale() ) ) )
550        {
551            changedState = true;
552        }
553 
554        return changedState;
555    }
556 
557    //------------------------------------------------------DefaultTaskMonitor--
558    //--Messages----------------------------------------------------------------
559 
560// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausMessages
561    // This section is managed by jdtaus-container-mojo.
562 
563    /**
564     * Gets the text of message <code>threadStarted</code>.
565     * <blockquote><pre>Neuen Thread gestartet. Abtastperiode {0,number}ms.</pre></blockquote>
566     * <blockquote><pre>New thread started. Period {0,number}ms.</pre></blockquote>
567     *
568     * @param locale The locale of the message instance to return.
569     * @param periodMillis Period of the started thread.
570     *
571     * @return Information about a started thread.
572     */
573    private String getThreadStartedMessage( final Locale locale,
574            final java.lang.Number periodMillis )
575    {
576        return ContainerFactory.getContainer().
577            getMessage( this, "threadStarted", locale,
578                new Object[]
579                {
580                    periodMillis
581                });
582 
583    }
584 
585    /**
586     * Gets the text of message <code>threadDied</code>.
587     * <blockquote><pre>Thread abnorm beendet. Konsultieren Sie die Protokolle für mögliche Ursachen.</pre></blockquote>
588     * <blockquote><pre>The monitor thread terminated abnormally. Consult the logs for any causes.</pre></blockquote>
589     *
590     * @param locale The locale of the message instance to return.
591     *
592     * @return Information about a dead thread.
593     */
594    private String getThreadDiedMessage( final Locale locale )
595    {
596        return ContainerFactory.getContainer().
597            getMessage( this, "threadDied", locale, null );
598 
599    }
600 
601    /**
602     * Gets the text of message <code>taskAlreadyStarted</code>.
603     * <blockquote><pre>Ein Vorgang mit Beschreibung {0} wurde bereits um {1,time,long} gestartet.</pre></blockquote>
604     * <blockquote><pre>A task with description {0} already has been started at {1,time,long}.</pre></blockquote>
605     *
606     * @param locale The locale of the message instance to return.
607     * @param taskDescription Description of the already running task.
608     * @param startTime Time the already running task got started.
609     *
610     * @return Information about an already running task.
611     */
612    private String getTaskAlreadyStartedMessage( final Locale locale,
613            final java.lang.String taskDescription,
614            final java.util.Date startTime )
615    {
616        return ContainerFactory.getContainer().
617            getMessage( this, "taskAlreadyStarted", locale,
618                new Object[]
619                {
620                    taskDescription,
621                    startTime
622                });
623 
624    }
625 
626// </editor-fold>//GEN-END:jdtausMessages
627 
628    //----------------------------------------------------------------Messages--
629}

[all classes][org.jdtaus.core.monitor.ri]
EMMA 2.1.5320 (stable) (C) Vladimir Roubtsov