001/*
002 *  jDTAUS Core Utilities
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.util;
022
023import java.io.File;
024import java.net.URL;
025import org.jdtaus.core.container.ContainerFactory;
026import org.jdtaus.core.container.Implementation;
027import org.jdtaus.core.container.ModelFactory;
028import org.jdtaus.core.container.Specification;
029import org.jdtaus.core.lang.ExceptionEvent;
030import org.jdtaus.core.lang.ExceptionListener;
031import org.jdtaus.core.messages.BugReportMessage;
032import org.jdtaus.core.messages.ExceptionMessage;
033import org.jdtaus.core.messages.UndefinedApplicationStateMessage;
034import org.jdtaus.core.text.Message;
035import org.jdtaus.core.text.MessageEvent;
036import org.jdtaus.core.text.Messages;
037import org.jdtaus.core.text.spi.ApplicationLogger;
038
039/**
040 * {@code ExceptionListener} resolving exceptions to corresponding application
041 * messages.
042 *
043 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
044 * @version $JDTAUS: ExceptionMessageProducer.java 8795 2012-12-03 16:53:46Z schulte $
045 *
046 * @see #onException(ExceptionEvent)
047 * @see org.jdtaus.core.text.util.SwingMessagePane
048 * @see org.jdtaus.core.text.util.MessageLogger
049 */
050public final class ExceptionMessageProducer implements ExceptionListener
051{
052    //--Constructors------------------------------------------------------------
053
054// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausConstructors
055    // This section is managed by jdtaus-container-mojo.
056
057// </editor-fold>//GEN-END:jdtausConstructors
058
059    //------------------------------------------------------------Constructors--
060    //--Dependencies------------------------------------------------------------
061
062// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausDependencies
063    // This section is managed by jdtaus-container-mojo.
064
065    /**
066     * Gets the configured <code>ApplicationLogger</code> implementation.
067     *
068     * @return The configured <code>ApplicationLogger</code> implementation.
069     */
070    private ApplicationLogger getApplicationLogger()
071    {
072        return (ApplicationLogger) ContainerFactory.getContainer().
073            getDependency( this, "ApplicationLogger" );
074
075    }
076
077// </editor-fold>//GEN-END:jdtausDependencies
078
079    //------------------------------------------------------------Dependencies--
080    //--Properties--------------------------------------------------------------
081
082// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausProperties
083    // This section is managed by jdtaus-container-mojo.
084
085// </editor-fold>//GEN-END:jdtausProperties
086
087    //--------------------------------------------------------------Properties--
088    //--ExceptionListener-------------------------------------------------------
089
090    /**
091     * {@inheritDoc}
092     * <p>This method resolves exceptions provided by an application's
093     * {@code ExceptionEventSource} to corresponding {@code MessageEvent}s which
094     * an application may react to by registering a listener to its
095     * {@code MessageEventSource}. Messages for checked exceptions are resolved
096     * by using any available {@code ExceptionMessageResolver} implementation
097     * stopping at the first implementation not returning {@code null}.
098     * For exceptions which are instances of {@code RuntimeException} an
099     * additional message informing the user that the application's state is
100     * undefined and that a restart is recommended is added to the produced
101     * {@code MessageEvent}. Optionally an additional message informing the user
102     * on how to report a bug is added to the produced {@code MessageEvent} if
103     * the instance got constructed using the constructor taking that
104     * information.</p>
105     *
106     * @param event The event holding the exception.
107     *
108     * @see ExceptionMessageResolver#resolve(Exception)
109     */
110    public void onException( final ExceptionEvent event )
111    {
112        if ( event != null )
113        {
114            final Throwable exception = event.getException();
115            final Throwable rootCause = event.getRootCause();
116            final Messages messages = new Messages();
117
118            messages.addMessage( new ExceptionMessage( exception ) );
119
120            if ( rootCause instanceof RuntimeException )
121            {
122                messages.addMessage( new UndefinedApplicationStateMessage() );
123
124                if ( this.logDirectory != null )
125                {
126                    messages.addMessage( new BugReportMessage(
127                        this.logDirectory, this.trackerUrl,
128                        this.reportAddress ) );
129
130                }
131            }
132            else if ( rootCause instanceof Exception )
133            {
134                final Message[] resolved =
135                    this.resolveMessages( (Exception) rootCause );
136
137                if ( resolved != null )
138                {
139                    messages.addMessages( resolved );
140                }
141            }
142
143            this.getApplicationLogger().log(
144                new MessageEvent( this,
145                                  messages.getMessages(),
146                                  MessageEvent.ERROR ) );
147
148        }
149    }
150
151    //-------------------------------------------------------ExceptionListener--
152    //--ExceptionMessageProducer------------------------------------------------
153
154    /**
155     * Directory holding the application's log files.
156     * @serial
157     */
158    private File logDirectory;
159
160    /**
161     * URL of the online bugtracking system.
162     * @serial
163     */
164    private URL trackerUrl;
165
166    /**
167     * Mail address to send the bugreport to.
168     * @serial
169     */
170    private String reportAddress;
171
172    /** Creates a new {@code ExceptionMessageProducer} instance. */
173    public ExceptionMessageProducer()
174    {
175        super();
176        this.logDirectory = null;
177        this.trackerUrl = null;
178        this.reportAddress = null;
179    }
180
181    /**
182     * Creates a new {@code ExceptionMessageProducer} instance taking the
183     * application's logfile directory.
184     *
185     * @param logDirectory The directory holding the application's logfiles.
186     *
187     * @throws NullPointerException if {@code logDirectory} is {@code null}.
188     *
189     * @since 1.14
190     */
191    public ExceptionMessageProducer( final File logDirectory )
192    {
193        super();
194        if ( logDirectory == null )
195        {
196            throw new NullPointerException( "logDirectory" );
197        }
198
199        this.logDirectory = logDirectory;
200        this.trackerUrl = null;
201        this.reportAddress = null;
202    }
203
204    /**
205     * Creates a new {@code ExceptionMessageProducer} instance taking the
206     * application's logfile directory and an URL to the application's online
207     * bugtracking system.
208     *
209     * @param logDirectory The directory holding the application's logfiles.
210     * @param trackerUrl An URL to the application's online bugtracking system.
211     *
212     * @throws NullPointerException if either {@code logDirectory} or
213     * {@code trackerUrl} is {@code null}.
214     *
215     * @since 1.14
216     */
217    public ExceptionMessageProducer( final File logDirectory,
218                                     final URL trackerUrl )
219    {
220        super();
221        if ( logDirectory == null )
222        {
223            throw new NullPointerException( "logDirectory" );
224        }
225        if ( trackerUrl == null )
226        {
227            throw new NullPointerException( "trackerUrl" );
228        }
229
230        this.logDirectory = logDirectory;
231        this.trackerUrl = trackerUrl;
232        this.reportAddress = null;
233    }
234
235    /**
236     * Creates a new {@code ExceptionMessageProducer} instance taking the
237     * application's logfile directory and an email address where to send
238     * bugreports to.
239     *
240     * @param logDirectory The directory holding the application's logfiles.
241     * @param reportAddress An email address to alternatively send bugreports
242     * to.
243     *
244     * @throws NullPointerException if either {@code logDirectory} or
245     * {@code reportAddress} is {@code null}.
246     *
247     * @since 1.14
248     */
249    public ExceptionMessageProducer( final File logDirectory,
250                                     final String reportAddress )
251    {
252        super();
253        if ( logDirectory == null )
254        {
255            throw new NullPointerException( "logDirectory" );
256        }
257        if ( reportAddress == null )
258        {
259            throw new NullPointerException( "reportAddress" );
260        }
261
262        this.logDirectory = logDirectory;
263        this.trackerUrl = null;
264        this.reportAddress = reportAddress;
265    }
266
267    /**
268     * Creates a new {@code ExceptionMessageProducer} instance taking the
269     * application's logfile directory, an URL to the application's online
270     * bugtracking system, and an email address where to send bugreports to
271     * alternatively.
272     *
273     * @param logDirectory The directory holding the application's logfiles.
274     * @param trackerUrl An URL to the application's online bugtracking system.
275     * @param reportAddress An email address to alternatively send bugreports
276     * to.
277     *
278     * @throws NullPointerException if either {@code logDirectory},
279     * {@code trackerUrl} or {@code reportAddress} is {@code null}.
280     */
281    public ExceptionMessageProducer( final File logDirectory,
282                                     final URL trackerUrl,
283                                     final String reportAddress )
284    {
285        super();
286        if ( logDirectory == null )
287        {
288            throw new NullPointerException( "logDirectory" );
289        }
290        if ( trackerUrl == null )
291        {
292            throw new NullPointerException( "trackerUrl" );
293        }
294        if ( reportAddress == null )
295        {
296            throw new NullPointerException( "reportAddress" );
297        }
298
299        this.logDirectory = logDirectory;
300        this.trackerUrl = trackerUrl;
301        this.reportAddress = reportAddress;
302    }
303
304    /**
305     * Resolves application messages for a given exception by querying any
306     * available {@code ExceptionMessageResolver} implementation stopping at the
307     * first implementation not returning {@code null}.
308     *
309     * @param exception The exception to resolve application messages for.
310     *
311     * @throws NullPointerException if {@code exception} is {@code null}.
312     */
313    private Message[] resolveMessages( final Exception exception )
314    {
315        if ( exception == null )
316        {
317            throw new NullPointerException( "exception" );
318        }
319
320        Message[] messages = null;
321        final Specification spec = ModelFactory.getModel().getModules().
322            getSpecification( ExceptionMessageResolver.class.getName() );
323
324        final Implementation[] resolvers = spec.getImplementations().
325            getImplementations();
326
327        for ( int i = resolvers.length - 1; i >= 0 && messages == null; i-- )
328        {
329            final ExceptionMessageResolver resolver =
330                (ExceptionMessageResolver) ContainerFactory.getContainer().
331                getObject( ExceptionMessageResolver.class,
332                           resolvers[i].getName() );
333
334            messages = resolver.resolve( exception );
335        }
336
337        return messages;
338    }
339
340    //------------------------------------------------ExceptionMessageProducer--
341}