001/*
002 *  jDTAUS Core RI JDK 1.4 Executor
003 *  Copyright (C) 2005 Christian Schulte
004 *  <cs@schulte.it>
005 *
006 *  This library is free software; you can redistribute it and/or
007 *  modify it under the terms of the GNU Lesser General Public
008 *  License as published by the Free Software Foundation; either
009 *  version 2.1 of the License, or any later version.
010 *
011 *  This library is distributed in the hope that it will be useful,
012 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
013 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014 *  Lesser General Public License for more details.
015 *
016 *  You should have received a copy of the GNU Lesser General Public
017 *  License along with this library; if not, write to the Free Software
018 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
019 *
020 */
021package org.jdtaus.core.lang.ri.executor;
022
023import java.util.ArrayList;
024import java.util.List;
025import javax.swing.event.EventListenerList;
026import org.jdtaus.core.container.ContainerFactory;
027import org.jdtaus.core.lang.ExceptionEvent;
028import org.jdtaus.core.lang.ExceptionListener;
029import org.jdtaus.core.lang.spi.Executor;
030
031/**
032 * jDTAUS Core SPI JDK 1.4 {@code Executor} reference implementation.
033 *
034 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
035 * @version $JDTAUS: Jdk14Executor.java 8641 2012-09-27 06:45:17Z schulte $
036 *
037 * @see org.jdtaus.core.container.Container
038 */
039public class Jdk14Executor implements Executor
040{
041    //--Constructors------------------------------------------------------------
042
043// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausConstructors
044    // This section is managed by jdtaus-container-mojo.
045
046    /** Standard implementation constructor <code>org.jdtaus.core.lang.ri.executor.Jdk14Executor</code>. */
047    public Jdk14Executor()
048    {
049        super();
050    }
051
052// </editor-fold>//GEN-END:jdtausConstructors
053
054    //------------------------------------------------------------Constructors--
055    //--Properties--------------------------------------------------------------
056
057// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausProperties
058    // This section is managed by jdtaus-container-mojo.
059
060    /**
061     * Gets the value of property <code>defaultThreadGroupName</code>.
062     *
063     * @return Default name of the thread group backing the implementation.
064     */
065    private java.lang.String getDefaultThreadGroupName()
066    {
067        return (java.lang.String) ContainerFactory.getContainer().
068            getProperty( this, "defaultThreadGroupName" );
069
070    }
071
072// </editor-fold>//GEN-END:jdtausProperties
073
074    //--------------------------------------------------------------Properties--
075    //--ExceptionEventSource----------------------------------------------------
076
077    /** Holds {@code ExceptionListener}s. */
078    private final EventListenerList listeners = new EventListenerList();
079
080    public void addExceptionListener( final ExceptionListener listener )
081    {
082        if ( listener == null )
083        {
084            throw new NullPointerException( "listener" );
085        }
086
087        synchronized ( this.listeners )
088        {
089            this.listeners.add( ExceptionListener.class, listener );
090        }
091    }
092
093    public void removeExceptionListener( final ExceptionListener listener )
094    {
095        if ( listener == null )
096        {
097            throw new NullPointerException( "listener" );
098        }
099
100        synchronized ( this.listeners )
101        {
102            this.listeners.remove( ExceptionListener.class, listener );
103        }
104    }
105
106    public ExceptionListener[] getExceptionListeners()
107    {
108        synchronized ( this.listeners )
109        {
110            return (ExceptionListener[]) this.listeners.getListeners(
111                ExceptionListener.class );
112
113        }
114    }
115
116    //----------------------------------------------------ExceptionEventSource--
117    //--ExceptionHandler--------------------------------------------------------
118
119    /** List of exception handled by the instance. */
120    private final List handledExceptions = new ArrayList( 255 );
121
122    public ExceptionEvent[] getExceptionEvents()
123    {
124        synchronized ( this.handledExceptions )
125        {
126            return (ExceptionEvent[]) this.handledExceptions.toArray(
127                new ExceptionEvent[ this.handledExceptions.size() ] );
128
129        }
130    }
131
132    public void handle( final Throwable t )
133    {
134        if ( t == null )
135        {
136            throw new NullPointerException( "t" );
137        }
138
139        final ExceptionEvent evt =
140            new ExceptionEvent( this, Thread.currentThread(), t );
141
142        this.fireOnException( evt );
143    }
144
145    //--------------------------------------------------------ExceptionHandler--
146    //--Executor----------------------------------------------------------------
147
148    public void executeAsynchronously( final Runnable runnable )
149    {
150        if ( runnable == null )
151        {
152            throw new NullPointerException( "runnable" );
153        }
154
155        new Thread( this.getThreadGroup(), runnable ).start();
156    }
157
158    //----------------------------------------------------------------Executor--
159    //--Jdk14Executor-----------------------------------------------------------
160
161    /** The name of the thread group backing the instance. */
162    private String threadGroupName;
163
164    /**
165     * {@code ThreadGroup} of threads executing the given {@code Runnable}s
166     * asynchronously.
167     */
168    private ThreadGroup threadGroup;
169
170    /**
171     * Creates a new {@code Jdk14Executor} instance taking the name of the
172     * thread group backing the instance.
173     *
174     * @param threadGroupName the name of the thread group backing the instance.
175     */
176    public Jdk14Executor( final String threadGroupName )
177    {
178        if ( threadGroupName != null )
179        {
180            this.threadGroupName = threadGroupName;
181        }
182    }
183
184    /**
185     * Group of threads executing the given {@code Runnable}s asynchronously.
186     */
187    private final class ThreadGroup extends java.lang.ThreadGroup
188    {
189
190        /**
191         * Creates a new {@code ExecutorThreadGroup} instance taking its name.
192         *
193         * @param name the name of the new thread group.
194         */
195        ThreadGroup( final String name )
196        {
197            super( name );
198        }
199
200        /**
201         * {@inheritdDoc}
202         * <p>This method notifies any registered {@code ExceptionListener}s
203         * about the given exception if it is not an instance of
204         * {@code ThreadDeath}. For instances of {@code ThreadDeath} the super
205         * classe's {@code uncaughtException(Thread, Throwable)} method is
206         * called.</p>
207         *
208         * @param t the thread that is about to exit.
209         * @param e the uncaught exception.
210         */
211        public void uncaughtException( final Thread t, final Throwable e )
212        {
213            if ( e instanceof ThreadDeath )
214            {
215                super.uncaughtException( t, e );
216            }
217            else
218            {
219                fireOnException(
220                    new ExceptionEvent( Jdk14Executor.this, t, e ) );
221
222            }
223        }
224
225    }
226
227    /**
228     * Gets the value of property {@code threadGroupName}.
229     *
230     * @return the name of the thread group backing the instance.
231     */
232    private String getThreadGroupName()
233    {
234        if ( this.threadGroupName == null )
235        {
236            this.threadGroupName = this.getDefaultThreadGroupName();
237        }
238
239        return this.threadGroupName;
240    }
241
242    /**
243     * Gets the group of threads executing the given {@code Runnable}s
244     * asynchronously.
245     *
246     * @return the group of threads executing the given {@code Runnable}s
247     * asynchronously.
248     */
249    private ThreadGroup getThreadGroup()
250    {
251        if ( this.threadGroup == null )
252        {
253            this.threadGroup =
254                new Jdk14Executor.ThreadGroup( this.getThreadGroupName() );
255
256        }
257
258        return this.threadGroup;
259    }
260
261    /**
262     * Notifies all registered {@code ExceptionListener}s about a given
263     * {@code ExceptionEvent}.
264     *
265     * @param e the event to provide to the listeners.
266     *
267     * @throws NullPointerException if {@code e} is {@code null}.
268     */
269    private void fireOnException( final ExceptionEvent e )
270    {
271        if ( e == null )
272        {
273            throw new NullPointerException( "e" );
274        }
275
276        synchronized ( this.handledExceptions )
277        {
278            this.handledExceptions.add( e );
279        }
280
281        synchronized ( this.listeners )
282        {
283            final Object[] list = this.listeners.getListenerList();
284            for ( int i = list.length - 2; i >= 0; i -= 2 )
285            {
286                if ( list[i] == ExceptionListener.class )
287                {
288                    ( (ExceptionListener) list[i + 1] ).onException( e );
289                }
290            }
291        }
292
293        final ExceptionListener[] exceptionListener =
294            this.getExceptionListener();
295
296        for ( int i = exceptionListener.length - 1; i >= 0; i-- )
297        {
298            exceptionListener[i].onException( e );
299        }
300    }
301
302    //-----------------------------------------------------------Jdk14Executor--
303    //--Dependencies------------------------------------------------------------
304
305// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausDependencies
306    // This section is managed by jdtaus-container-mojo.
307
308    /**
309     * Gets the configured <code>ExceptionListener</code> implementation.
310     *
311     * @return The configured <code>ExceptionListener</code> implementation.
312     */
313    private ExceptionListener[] getExceptionListener()
314    {
315        return (ExceptionListener[]) ContainerFactory.getContainer().
316            getDependency( this, "ExceptionListener" );
317
318    }
319
320// </editor-fold>//GEN-END:jdtausDependencies
321
322    //------------------------------------------------------------Dependencies--
323}