Project

General

Profile

Download (20.2 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.persistence.hibernate.permission.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

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

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

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

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

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

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

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

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

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

    
148

    
149

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

    
163

    
164

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

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

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

    
201
        return contextInfo;
202
    }
203

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

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

    
212
        StringWriter sw = new StringWriter();
213

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

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

    
221
        return stackTraceAndContextInfo.toString();
222
    }
223

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

    
227

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

    
232

    
233

    
234
        return scontextInfoStringBuffer.toString();
235
    }
236

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

    
241

    
242

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

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

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

    
270

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
417
                }
418

    
419

    
420
            }
421
        });
422
    }
423

    
424

    
425

    
426

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

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

    
451

    
452

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

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

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

    
504

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

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

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

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

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

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

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

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

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

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

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

    
615
}
(30-30/39)