EMMA Coverage Report (generated Tue Jan 14 02:29:45 CET 2014)
[all classes][org.jdtaus.core.monitor.ri]

COVERAGE SUMMARY FOR SOURCE FILE [DefaultTaskMonitor.java]

nameclass, %method, %block, %line, %
DefaultTaskMonitor.java100% (3/3)92%  (22/24)74%  (488/657)78%  (112.8/145)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class DefaultTaskMonitor100% (1/1)89%  (17/19)71%  (396/555)76%  (89.2/118)
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)
removeTaskListener (TaskListener): void 100% (1/1)35%  (7/20)50%  (2/4)
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)
checkMonitorThread (): 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)90%  (89/99)86%  (21.6/25)
run (): void 100% (1/1)71%  (12/17)70%  (5.6/8)
checkTasks (): boolean 100% (1/1)90%  (44/49)89%  (8/9)
DefaultTaskMonitor$MonitorThread (DefaultTaskMonitor, long): void 100% (1/1)100% (10/10)100% (4/4)
start (): void 100% (1/1)100% (23/23)100% (4/4)
     
class DefaultTaskMonitor$TaskState100% (1/1)100% (1/1)100% (3/3)100% (2/2)
DefaultTaskMonitor$TaskState (): void 100% (1/1)100% (3/3)100% (2/2)

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 8787 2012-12-03 02:13:32Z 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.fireTaskEvent( new TaskEvent( task, TaskEvent.STARTED ) );
181            this.createTaskState( task );
182            this.checkMonitorThread();
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        private TaskState()
270        {
271            super();
272        }
273 
274    }
275 
276    /** Thread monitoring all currently running {@code Task}s for changes. */
277    private final class MonitorThread extends Thread
278    {
279 
280        /** Milliseconds per poll interval. */
281        private final long pollIntervalMillis;
282 
283        /** Creates a new {@code MonitorThread} instance. */
284        private MonitorThread( final long pollIntervalMillis )
285        {
286            super( "DefaultTaskMonitor" );
287            this.pollIntervalMillis = pollIntervalMillis;
288        }
289 
290        /** {@inheritDoc} */
291        public void run()
292        {
293            boolean monitoring = true;
294 
295            while ( monitoring )
296            {
297                try
298                {
299                    Thread.sleep( this.pollIntervalMillis );
300                    monitoring = this.checkTasks();
301                }
302                catch ( final InterruptedException e )
303                {
304                    monitoring = this.checkTasks();
305                }
306            }
307        }
308 
309        public void start()
310        {
311            super.start();
312 
313            if ( getLogger().isDebugEnabled() )
314            {
315                getLogger().debug( getThreadStartedMessage(
316                    getLocale(), new Long( this.pollIntervalMillis ) ) );
317 
318            }
319        }
320 
321        /**
322         * Checks the state of all currently running tasks for changes and
323         * fires corresponding events.
324         */
325        private boolean checkTasks()
326        {
327            synchronized ( DefaultTaskMonitor.this.stateMap )
328            {
329                for ( final Iterator it = DefaultTaskMonitor.this.stateMap.
330                    keySet().iterator(); it.hasNext(); )
331                {
332                    final Task task = (Task) it.next();
333                    if ( changedState( task ) )
334                    {
335                        fireTaskEvent( new TaskEvent(
336                            task, TaskEvent.CHANGED_STATE ) );
337 
338                    }
339                }
340 
341                return !DefaultTaskMonitor.this.stateMap.isEmpty();
342            }
343        }
344 
345    }
346 
347    /**
348     * Gets the monitor thread.
349     *
350     * @return the monitor thread.
351     */
352    private synchronized void checkMonitorThread()
353    {
354        if ( this.monitorThread == null
355             || !this.monitorThread.isAlive() )
356        {
357            this.monitorThread =
358                new MonitorThread( this.getPollIntervalMillis() );
359 
360            this.monitorThread.start();
361        }
362    }
363 
364    /**
365     * Notifies all registered {@code TaskListener}s about {@code TaskEvent}s.
366     *
367     * @param e The event to be provided to the listeners.
368     */
369    private void fireTaskEvent( final TaskEvent e )
370    {
371        if ( e == null )
372        {
373            throw new NullPointerException( "e" );
374        }
375 
376 
377        final Object[] listeners = this.taskListeners.getListenerList();
378        for ( int i = listeners.length - 2; i >= 0; i -= 2 )
379        {
380            if ( listeners[i] == TaskListener.class )
381            {
382                ( (TaskListener) listeners[i + 1] ).onTaskEvent( e );
383            }
384        }
385 
386        final TaskListener[] taskListener = this.getTaskListener();
387        for ( int i = taskListener.length - 1; i >= 0; i-- )
388        {
389            taskListener[i].onTaskEvent( e );
390        }
391    }
392 
393    /**
394     * Caches the state of a {@code Task}.
395     *
396     * @param task the task to cache state for.
397     *
398     * @throws NullPointerException if {@code task} is {@code null}.
399     * @throws IllegalStateException if the cache already holds state for
400     * {@code task}.
401     */
402    private void createTaskState( final Task task )
403    {
404        final TaskState state = new TaskState();
405        state.cancelable = task.isCancelable();
406        state.indeterminate = task.isIndeterminate();
407        state.cancelled = state.cancelable
408                          ? task.isCancelled()
409                          : false;
410 
411        state.progressDescription = task.getProgressDescription();
412 
413        if ( state.indeterminate )
414        {
415            state.maximum = Integer.MIN_VALUE;
416            state.minimum = Integer.MIN_VALUE;
417            state.progress = Integer.MIN_VALUE;
418        }
419        else
420        {
421            state.maximum = task.getMaximum();
422            state.minimum = task.getMinimum();
423            state.progress = task.getProgress();
424        }
425 
426        if ( this.stateMap.put( task, state ) != null )
427        {
428            throw new IllegalStateException( this.getTaskAlreadyStartedMessage(
429                this.getLocale(),
430                task.getDescription().getText( this.getLocale() ),
431                new Date( task.getTimestamp() ) ) );
432 
433        }
434    }
435 
436    /**
437     * Removes the cached state of a {@code Task}.
438     *
439     * @param task the task to remove the cached state of.
440     *
441     * @throws NullPointerException if {@code task} is {@code null}.
442     */
443    private void removeTaskState( final Task task )
444    {
445        if ( task == null )
446        {
447            throw new NullPointerException( "task" );
448        }
449 
450        this.stateMap.remove( task );
451    }
452 
453    /**
454     * Checks the state of a given task for changes.
455     *
456     * @param task the task to check for state changes.
457     *
458     * @return {@code true} if the state of {@code task} changed since the last
459     * time this method got called; {@code false} if the state did not change.
460     *
461     * @throws NullPointerException if {@code task} is {@code null}.
462     * @throws IllegalStateException if no cached state exists for {@code task}.
463     */
464    private boolean changedState( final Task task )
465    {
466        if ( task == null )
467        {
468            throw new NullPointerException( "task" );
469        }
470 
471 
472        boolean changedState = false;
473        final TaskState state = (TaskState) this.stateMap.get( task );
474 
475        if ( state == null )
476        {
477            throw new IllegalStateException();
478        }
479 
480        if ( state.indeterminate )
481        {
482            state.indeterminate = task.isIndeterminate();
483            if ( !state.indeterminate )
484            {
485                state.minimum = task.getMinimum();
486                state.maximum = task.getMaximum();
487                state.progress = task.getProgress();
488                changedState = true;
489            }
490        }
491        else
492        {
493            state.indeterminate = task.isIndeterminate();
494            if ( state.indeterminate )
495            {
496                changedState = true;
497            }
498            else
499            {
500                if ( state.minimum != task.getMinimum() )
501                {
502                    state.minimum = task.getMinimum();
503                    changedState = true;
504                }
505                if ( state.maximum != task.getMaximum() )
506                {
507                    state.maximum = task.getMaximum();
508                    changedState = true;
509                }
510                if ( state.progress != task.getProgress() )
511                {
512                    state.progress = task.getProgress();
513                    changedState = true;
514                }
515            }
516        }
517 
518        if ( state.cancelable )
519        {
520            state.cancelable = task.isCancelable();
521            if ( !state.cancelable )
522            {
523                changedState = true;
524            }
525            else
526            {
527                if ( state.cancelled != task.isCancelled() )
528                {
529                    state.cancelled = task.isCancelled();
530                    changedState = true;
531                }
532            }
533        }
534        else
535        {
536            state.cancelable = task.isCancelable();
537            if ( !state.cancelable )
538            {
539                state.cancelled = false;
540                changedState = true;
541            }
542        }
543 
544        if ( state.progressDescription != task.getProgressDescription() )
545        {
546            state.progressDescription = task.getProgressDescription();
547            changedState = true;
548        }
549        else if ( state.progressDescription != null
550                  && !state.progressDescription.getText( this.getLocale() ).
551            equals( task.getProgressDescription().getText(
552            this.getLocale() ) ) )
553        {
554            changedState = true;
555        }
556 
557        return changedState;
558    }
559 
560    //------------------------------------------------------DefaultTaskMonitor--
561    //--Messages----------------------------------------------------------------
562 
563// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausMessages
564    // This section is managed by jdtaus-container-mojo.
565 
566    /**
567     * Gets the text of message <code>threadStarted</code>.
568     * <blockquote><pre>Neuen Thread gestartet. Abtastperiode {0,number}ms.</pre></blockquote>
569     * <blockquote><pre>New thread started. Period {0,number}ms.</pre></blockquote>
570     *
571     * @param locale The locale of the message instance to return.
572     * @param periodMillis Period of the started thread.
573     *
574     * @return Information about a started thread.
575     */
576    private String getThreadStartedMessage( final Locale locale,
577            final java.lang.Number periodMillis )
578    {
579        return ContainerFactory.getContainer().
580            getMessage( this, "threadStarted", locale,
581                new Object[]
582                {
583                    periodMillis
584                });
585 
586    }
587 
588    /**
589     * Gets the text of message <code>taskAlreadyStarted</code>.
590     * <blockquote><pre>Ein Vorgang mit Beschreibung {0} wurde bereits um {1,time,long} gestartet.</pre></blockquote>
591     * <blockquote><pre>A task with description {0} already has been started at {1,time,long}.</pre></blockquote>
592     *
593     * @param locale The locale of the message instance to return.
594     * @param taskDescription Description of the already running task.
595     * @param startTime Time the already running task got started.
596     *
597     * @return Information about an already running task.
598     */
599    private String getTaskAlreadyStartedMessage( final Locale locale,
600            final java.lang.String taskDescription,
601            final java.util.Date startTime )
602    {
603        return ContainerFactory.getContainer().
604            getMessage( this, "taskAlreadyStarted", locale,
605                new Object[]
606                {
607                    taskDescription,
608                    startTime
609                });
610 
611    }
612 
613// </editor-fold>//GEN-END:jdtausMessages
614 
615    //----------------------------------------------------------------Messages--
616}

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