Project

General

Profile

Download (20.3 KB) Statistics
| Branch: | Tag: | Revision:
1
package eu.etaxonomy.taxeditor.model;
2

    
3
import java.io.PrintWriter;
4
import java.io.StringWriter;
5
import java.util.ArrayList;
6
import java.util.List;
7

    
8
import org.apache.commons.lang.exception.ExceptionUtils;
9
import org.apache.log4j.Logger;
10
import org.eclipse.core.runtime.IStatus;
11
import org.eclipse.core.runtime.MultiStatus;
12
import org.eclipse.core.runtime.Platform;
13
import org.eclipse.core.runtime.Status;
14
import org.eclipse.jface.dialogs.MessageDialog;
15
import org.eclipse.swt.widgets.Display;
16

    
17
import eu.etaxonomy.cdm.test.integration.SecurityExceptionUtils;
18
import eu.etaxonomy.taxeditor.store.CdmStore;
19
import eu.etaxonomy.taxeditor.store.internal.TaxeditorStorePlugin;
20

    
21
/**
22
 * Utility class which handles all the messaging information generated by the
23
 * Editor.
24
 *
25
 * This includes logging as well as dialogs.
26
 *
27
 * @author cmathew
28
 *
29
 */
30
public class MessagingUtils {
31
    public final static String UNEXPECTED_ERROR_MESSAGE = "This is an unexpected error.";
32
    public final static String CONTACT_MESSAGE = System.getProperty("line.separator") +  "Please contact EDIT Support (EditSupport@bgbm.org) with the error trace below (click on the 'Details' button).";
33
    public final static String DEFAULT_MESSAGE = "Error thrown but no associated message";
34
    public final static String CONNECTION_FAILURE_MESSAGE = "The connection to the remote server has been broken";
35
    public final static String REMOTE_ACCESS_FAILURE_MESSAGE = "Problem accessing remote server";
36
    public static final String WIDGET_IS_DISPOSED_MESSAGE = "A widget was called, which was already disposed";
37

    
38
    /**
39
     * Gets the Log4J logger for a given class
40
     *
41
     * @param clazz
42
     *            a {@link java.lang.Class} object.
43
     * @return a {@link org.apache.log4j.Logger} object.
44
     */
45
    public static Logger getLog4JLogger(Class clazz) {
46
        return Logger.getLogger(clazz);
47
    }
48

    
49
    /**
50
     * Logs details from a given Status object
51
     *
52
     * @param status
53
     * 				a {@link org.eclipse.core.runtime.IStatus} object.
54
     */
55
    private static void log(IStatus status) {
56
        TaxeditorStorePlugin.getDefault().getLog().log(status);
57
    }
58

    
59
    /**
60
     * Logs a status object as information.
61
     *
62
     * @param status
63
     *            a {@link org.eclipse.core.runtime.IStatus} object.
64
     */
65
    public static void info(IStatus status) {
66
        log(status);
67
    }
68

    
69
    /**
70
     * Logs a string as information.
71
     *
72
     * @param message
73
     *            a {@link java.lang.String} object.
74
     */
75
    public static void info(String message) {
76
        IStatus status = new Status(IStatus.INFO, AbstractUtility.getPluginId(), message);
77
        info(status);
78
    }
79

    
80
    /**
81
     * Logs an exception from a given source as a warning.
82
     *
83
     * @param source
84
     * @param t
85
     */
86
    public static void warn(Class source, Throwable t) {
87
        IStatus status = new Status(IStatus.WARNING, AbstractUtility.getPluginId(), t.getMessage(), t);
88
        MessagingUtils.getLog4JLogger(source).warn(t);
89
        log(status);
90
    }
91

    
92
    /**
93
     * Logs a status object from a given source as a warning.
94
     *
95
     * @param source
96
     * @param status
97
     */
98
    public static void warn(Class source, IStatus status) {
99
        MessagingUtils.getLog4JLogger(source).warn(status.getMessage(), status.getException());
100
        log(status);
101
    }
102

    
103
    /**
104
     * Logs a string from a given source as a warning.
105
     *
106
     *
107
     * @param source
108
     *            a {@link java.lang.Class} object.
109
     * @param message
110
     *            a {@link java.lang.String} object.
111
     */
112
    public static void warn(Class source, String message) {
113
        IStatus status = new Status(IStatus.WARNING, AbstractUtility.getPluginId(), message);
114
        MessagingUtils.getLog4JLogger(source).warn(message);
115
        log(status);
116
    }
117

    
118
    /**
119
     * Logs a status object from a given source as an error.
120
     *
121
     *
122
     * @param source
123
     *            a {@link java.lang.Class} object.
124
     * @param status
125
     *            a {@link org.eclipse.core.runtime.IStatus} object.
126
     */
127
    public static void error(Class source, IStatus status) {
128
        getLog4JLogger(source)
129
        .error(status.getMessage(), status.getException());
130
        log(status);
131
    }
132

    
133
    /**
134
     * Logs a string and exception from a given source as an error.
135
     *
136
     *
137
     * @param source
138
     *            a {@link java.lang.Class} object.
139
     * @param message
140
     *            a {@link java.lang.String} object.
141
     * @param t
142
     *            a {@link java.lang.Throwable} object.
143
     */
144
    public static void error(Class source, String message, Throwable t) {
145
        IStatus status = new Status(IStatus.ERROR, AbstractUtility.getPluginId(), message, t);
146
        error(source, status);
147
    }
148

    
149

    
150

    
151
    /**
152
     * Logs an exception from a given source as an error.
153
     *
154
     *
155
     * @param source
156
     *            a {@link java.lang.Class} object.
157
     * @param t
158
     *            a {@link java.lang.Throwable} object.
159
     */
160
    public static void error(Class source, Throwable t) {
161
        error(source.getClass(), t.getMessage(), t);
162
    }
163

    
164

    
165

    
166
    /**
167
     * Returns a list of strings, providing info on,
168
     *  - login
169
     *  - editor version
170
     *  - server (address + source name)
171
     *  - db schema version
172
     *
173
     * @return
174
     */
175
    public static List<String> getContextInfo() {
176
        List<String> contextInfo = new ArrayList<String>();
177
        String name = "";
178
        String schemaVersion = "";
179
        String server = "";
180
        String version = "";
181
        String login = "";
182
        try {
183
            version = Platform.getBundle("eu.etaxonomy.taxeditor.application").getHeaders().get(org.osgi.framework.Constants.BUNDLE_VERSION);
184

    
185
            if(CdmStore.getActiveCdmSource() != null ) {
186
                login = CdmStore.getLoginManager().getAuthenticatedUser().getUsername();
187
                name = CdmStore.getActiveCdmSource().getName();
188
                schemaVersion = CdmStore.getActiveCdmSource().getDbSchemaVersion();
189
                server = CdmStore.getActiveCdmSource().getServer();
190
            }
191

    
192
        } catch (Exception e) {
193
            // Nothing to do
194
        }
195
        contextInfo.add("login : " + login);
196
        contextInfo.add("editor version : " + version);
197
        contextInfo.add("server : " + server + " / " + name);
198
        contextInfo.add("schema version : " + schemaVersion);
199
        contextInfo.add("os : " + System.getProperty("os.name")+" "+System.getProperty("os.version")+" "+System.getProperty("os.arch"));
200
        contextInfo.add("java : "+System.getProperty("java.version"));
201

    
202
        return contextInfo;
203
    }
204

    
205
    public static String getStackTraceAndContextInfo(Throwable t, List<String> contextInfo)  {
206
        StringBuffer stackTraceAndContextInfo = new StringBuffer();
207
        Throwable throwable = t;
208

    
209
        for(String infoItem : contextInfo) {
210
            stackTraceAndContextInfo.append(infoItem + System.getProperty("line.separator"));
211
        }
212

    
213
        StringWriter sw = new StringWriter();
214

    
215
        if(throwable == null) {
216
            throwable = getDefaultThrowable();
217
        }
218
        throwable.printStackTrace(new PrintWriter(sw));
219

    
220
        stackTraceAndContextInfo.append(sw.toString());
221

    
222
        return stackTraceAndContextInfo.toString();
223
    }
224

    
225
    public static String getContextInfo(List<String> contextInfo)  {
226
        StringBuffer scontextInfoStringBuffer = new StringBuffer();
227

    
228

    
229
        for(String infoItem : contextInfo) {
230
            scontextInfoStringBuffer.append(infoItem + System.getProperty("line.separator"));
231
        }
232

    
233

    
234

    
235
        return scontextInfoStringBuffer.toString();
236
    }
237

    
238
    private static Throwable getDefaultThrowable() {
239
        return new Throwable("Error thrown but no associated exception");
240
    }
241

    
242

    
243

    
244
    /**
245
     * Displays a {@link eu.etaxonomy.taxeditor.model.CdmErrorDialog}.
246
     *
247
     * @param title
248
     * @param source
249
     * @param t
250
     * @param contextInfo
251
     * @param message
252
     * @param status
253
     */
254
    private static void errorDialog(final String title,
255
            final Object source,
256
            final Throwable t,
257
            final List<String> contextInfo,
258
            final String message,
259
            final MultiStatus status,
260
            final boolean showReason) {
261

    
262
        Display.getDefault().asyncExec(new Runnable() {
263

    
264
            @Override
265
            public void run() {
266
                String stackTraceWithContext = getStackTraceAndContextInfo(t, contextInfo);
267
                CdmErrorDialog ced = new CdmErrorDialog(AbstractUtility.getShell(), title, message, status, stackTraceWithContext, showReason);
268
                ced.open();
269
                Class<? extends Object> clazz = source != null ? source.getClass() : this.getClass();
270

    
271

    
272
                IStatus singleStatus = new Status(IStatus.ERROR,
273
                        status.getPlugin(),
274
                        message,
275
                        new Exception(stackTraceWithContext));
276

    
277
                error(clazz, singleStatus);
278
            }
279
        });
280
    }
281

    
282
    public static void errorDialog(final String title,
283
            final Object source,
284
            final String message,
285
            final String pluginId,
286
            final Throwable t,
287
            boolean addContactMesg) {
288
        errorDialog(title, source, message, pluginId, t, addContactMesg, true);
289

    
290
    }
291
    /**
292
     * Displays a {@link eu.etaxonomy.taxeditor.model.CdmErrorDialog}.
293
     *
294
     * @param title
295
     * @param source
296
     * @param message
297
     * @param pluginId
298
     * @param t
299
     */
300
    public static void errorDialog(final String title,
301
            final Object source,
302
            final String message,
303
            final String pluginId,
304
            final Throwable t,
305
            boolean addContactMesg,
306
            boolean showReason) {
307

    
308
        Throwable throwable = t;
309
        StringBuffer sbStackTrace = new StringBuffer();
310

    
311
        // We need to build a MultiStatus object since the simple
312
        // idea of writing out the stack trace as a single string
313
        // leads to a single line on windows
314
        List<Status> childStatuses = new ArrayList<Status>();
315

    
316
        // add context info
317
        List<String> contextInfo = getContextInfo();
318
        for(String infoItem : contextInfo) {
319
            childStatuses.add(new Status(IStatus.ERROR, pluginId, infoItem));
320
        }
321

    
322
        if(throwable == null) {
323
            throwable = getDefaultThrowable();
324
        }
325

    
326
        int thCount = 0;
327
        int maxTraces = 4;
328

    
329
        for(Throwable th : ExceptionUtils.getThrowables(throwable)) {
330
            // add main exception
331
            if(thCount == 0) {
332
                for (StackTraceElement ste : th.getStackTrace()) {
333
                    childStatuses.add(new Status(IStatus.ERROR, pluginId, "  at " + ste.toString()));
334
                }
335
            } else {
336
                // add recursive causes
337
                if(th != null) {
338
                    childStatuses.add(new Status(IStatus.ERROR, pluginId, ""));
339
                    String msg = th.toString();
340
                    childStatuses.add(new Status(IStatus.ERROR, pluginId, "Caused by : " + msg));
341
                    int traceCount = 0;
342
                    for (StackTraceElement ste : th.getStackTrace()) {
343
                        // add only pre-defined number of trace elements
344
                        if(traceCount > maxTraces) {
345
                            childStatuses.add(new Status(IStatus.ERROR, pluginId, "  ...."));
346
                            break;
347
                        }
348
                        // build & add status
349
                        childStatuses.add(new Status(IStatus.ERROR, pluginId, "  at " + ste.toString()));
350
                        traceCount++;
351
                    }
352
                }
353
            }
354
            thCount++;
355
        }
356
        String finalMessage = message;
357

    
358
        if(finalMessage == null || finalMessage.isEmpty()) {
359
            finalMessage = DEFAULT_MESSAGE;
360
        }
361

    
362
        if(addContactMesg) {
363
            // add edit support contact info to message
364
            finalMessage += MessagingUtils.CONTACT_MESSAGE;
365
        }
366

    
367
        MultiStatus ms = new MultiStatus(pluginId,
368
                IStatus.ERROR,
369
                childStatuses.toArray(new Status[] {}),
370
                throwable.toString(),
371
                throwable);
372

    
373
        errorDialog(title, source, throwable, contextInfo, finalMessage, ms, showReason);
374
    }
375

    
376
    /**
377
     * Displays a dialog for an exception occurring in an operation.
378
     *
379
     * This will be either a {@link eu.etaxonomy.taxeditor.model.CdmErrorDialog} in case of a
380
     * security runtime exception or a warning {@link org.eclipse.jface.dialogs.MessageDialog} in
381
     * case of any other exception.
382
     *
383
     * @param title
384
     *            a {@link java.lang.String} object.
385
     * @param source
386
     *            a {@link java.lang.Object} object.
387
     * @param status
388
     *            a {@link org.eclipse.core.runtime.IStatus} object.
389
     */
390
    public static void operationDialog(final Object source,
391
            final Exception ex,
392
            final String pluginId,
393
            final String operationlabel,
394
            final String hint) {
395

    
396
        Display.getDefault().asyncExec(new Runnable() {
397

    
398
            @Override
399
            public void run() {
400
                MultiStatus info = null;
401
                String title = null;
402

    
403
                // FIXME cannot access TaxonomicEditorPlugin.PLUGIN_ID from here
404
                // String PID = TaxonomicEditorPlugin.PLUGIN_ID;
405
                String PID = "eu.etaxonomy.taxeditor.application";
406

    
407
                // checking security exceptions for every operation
408
                RuntimeException securityRuntimeException = SecurityExceptionUtils.findSecurityRuntimeException(ex);
409

    
410
                // in case of a security exception it is a warning, else it is an error
411
                if(securityRuntimeException != null){
412
                    title = "Your changes could not be saved!";
413
                    warningDialog(title, source, String.format("You are missing sufficient permissions for the operation \"%s\". %s", operationlabel, hint));
414
                } else {
415
                    title = "Error executing operation";
416
                    errorDialog(title, source, String.format("An error occured while executing %s. %s", operationlabel, hint), pluginId, ex, true);
417

    
418
                }
419

    
420

    
421
            }
422
        });
423
    }
424

    
425

    
426

    
427

    
428
    /**
429
     * Displays a question {@link org.eclipse.jface.dialogs.MessageDialog}.
430
     *
431
     * @param title
432
     *            a {@link java.lang.String} object.
433
     * @param message
434
     *            a {@link java.lang.String} object.
435
     * @return a boolean.
436
     */
437
    public static boolean confirmDialog(String title, String message) {
438
        return MessageDialog.openQuestion(AbstractUtility.getShell(), title, message);
439
    }
440

    
441
    /**
442
     * Displays a message {@link org.eclipse.jface.dialogs.MessageDialog}.
443
     *
444
     * @param title
445
     * @param source
446
     * @param message
447
     */
448
    public static void messageDialog(final String title, final Object source, final String message) {
449
        MessagingUtils.messageDialog(title, source, message, null, true);
450
    }
451

    
452

    
453

    
454
    /**
455
     * Displays an error {@link org.eclipse.jface.dialogs.MessageDialog}.
456
     *
457
     * @param title
458
     *            The dialogs title
459
     * @param source
460
     *            The object where the warning was generated (used by log4j)
461
     * @param message
462
     *            An informative String to be presented to the user
463
     * @param title
464
     *            The dialogs title
465
     * @param t
466
     *            a Throwable if one exists or null
467
     */
468
    public static void messageDialog(final String title,
469
            final Object source,
470
            final String message,
471
            final Throwable t) {
472
        MessagingUtils.messageDialog(title, source, message, t, true);
473
    }
474

    
475
    /**
476
     * Displays an error {@link org.eclipse.jface.dialogs.MessageDialog}.
477
     *
478
     * @param title
479
     *            The dialogs title
480
     * @param source
481
     *            The object where the warning was generated (used by log4j)
482
     * @param message
483
     *            An informative String to be presented to the user
484
     * @param title
485
     *            The dialogs title
486
     * @param t
487
     *            a Throwable if one exists or null
488
     */
489
    public static void messageDialog(final String title,
490
            final Object source,
491
            final String message,
492
            final Throwable t,
493
            boolean async) {
494
        if(async) {
495
            Display.getDefault().asyncExec(new Runnable() {
496

    
497
                @Override
498
                public void run() {
499
                    MessageDialog.openError(AbstractUtility.getShell(), title, message + getCauseRecursively(t));
500
                    Class<? extends Object> clazz = source != null ? source
501
                            .getClass() : this.getClass();
502
                            error(clazz, message, t);
503
                }
504

    
505

    
506
            });
507
        } else {
508
            MessageDialog.openError(AbstractUtility.getShell(), title, message + getCauseRecursively(t));
509
            Class<? extends Object> clazz = source != null ? source.getClass() : TaxeditorStorePlugin.class;
510
            error(clazz, message, t);
511
        }
512
    }
513

    
514
    public static String getCauseRecursively(Throwable t) {
515
        if(t == null){
516
            return "";
517
        }
518

    
519
        if(t.getCause() != null){
520
            return getCauseRecursively(t.getCause());
521
        }else{
522
            return String.format("\n\nException: %s\nMessage: %s", t.getClass().getSimpleName(), t.getMessage());
523
        }
524

    
525
    }
526
    /**
527
     * Displays a warning {@link org.eclipse.jface.dialogs.MessageDialog}.
528
     *
529
     * @param title
530
     * @param termBase
531
     * @param status
532
     */
533
    public static void warningDialog(String title, Object source,
534
            IStatus status) {
535
        MessagingUtils.warningDialog(title, source, status.getMessage());
536
    }
537

    
538
    /**
539
     * Standard warning dialog for the case when the application is not yet connected to the datasource
540
     *
541
     * @param source
542
     */
543
    public static void noDataSourceWarningDialog(Object source) {
544
        MessagingUtils
545
        .warningDialog(
546
                "Application is not connected to a datastore",
547
                source,
548
                "The requested operation is only available when "
549
                + "connected to a datasource. You may choose a datasource to connect to or create a new one in the datasource view.");
550
    }
551

    
552
    /**
553
     * Displays a warning {@link org.eclipse.jface.dialogs.MessageDialog}.
554
     *
555
     * @param title
556
     *            The dialogs title
557
     * @param source
558
     *            The object where the warning was generated (used by log4j)
559
     * @param message
560
     *            An informative String to be presented to the user
561
     */
562
    public static void warningDialog(final String title, final Object source, final String message) {
563
        Display.getDefault().asyncExec(new Runnable() {
564

    
565
            @Override
566
            public void run() {
567
                MessageDialog.openWarning(AbstractUtility.getShell(), title, message);
568
                Class<? extends Object> clazz = source != null ? source
569
                        .getClass() : AbstractUtility.class;
570
                        warn(clazz, message);
571
            }
572
        });
573
    }
574

    
575
    /**
576
     * Displays an information {@link org.eclipse.jface.dialogs.MessageDialog}.
577
     *
578
     * @param title
579
     * @param status
580
     */
581
    public static void informationDialog(final String title, final IStatus status) {
582
        MessagingUtils.informationDialog(title, status.getMessage());
583
    }
584

    
585
    /**
586
     * Displays an information {@link org.eclipse.jface.dialogs.MessageDialog}.
587
     *
588
     * @param title
589
     *            a {@link java.lang.String} object.
590
     * @param message
591
     *            a {@link java.lang.String} object.
592
     */
593
    public static void informationDialog(final String title,
594
            final String message) {
595
        Display.getDefault().asyncExec(new Runnable() {
596

    
597
            @Override
598
            public void run() {
599
                MessageDialog.openInformation(AbstractUtility.getShell(), title, message);
600
            }
601
        });
602
    }
603

    
604
    /**
605
     * Open a message box that informs the user about unimplemented
606
     * functionality. This method is for developer convenience.
607
     *
608
     * @param source
609
     *            a {@link java.lang.Object} object.
610
     */
611
    public static void notImplementedMessage(Object source) {
612
        warningDialog("Not yet implemented", source,
613
                "This functionality is not yet implemented.");
614
    }
615

    
616
}
(29-29/38)