Project

General

Profile

Download (19.6 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

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

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

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

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

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

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

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

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

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

    
146

    
147

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

    
161

    
162

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

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

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

    
199
        return contextInfo;
200
    }
201

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

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

    
210
        StringWriter sw = new StringWriter();
211

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

    
217
        stackTraceAndContextInfo.append(sw.toString());
218

    
219
        return stackTraceAndContextInfo.toString();
220
    }
221

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

    
225

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

    
230

    
231

    
232
        return scontextInfoStringBuffer.toString();
233
    }
234

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

    
239

    
240

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

    
258
        Display.getDefault().asyncExec(new Runnable() {
259

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

    
267

    
268
                IStatus singleStatus = new Status(IStatus.ERROR,
269
                        status.getPlugin(),
270
                        message,
271
                        new Exception(stackTraceWithContext));
272

    
273
                error(clazz, singleStatus);
274
            }
275
        });
276
    }
277

    
278
    /**
279
     * Displays a {@link eu.etaxonomy.taxeditor.model.CdmErrorDialog}.
280
     *
281
     * @param title
282
     * @param source
283
     * @param message
284
     * @param pluginId
285
     * @param t
286
     */
287
    public static void errorDialog(final String title,
288
            final Object source,
289
            final String message,
290
            final String pluginId,
291
            final Throwable t,
292
            boolean addContactMesg) {
293

    
294
        Throwable throwable = t;
295
        StringBuffer sbStackTrace = new StringBuffer();
296

    
297
        // We need to build a MultiStatus object since the simple
298
        // idea of writing out the stack trace as a single string
299
        // leads to a single line on windows
300
        List<Status> childStatuses = new ArrayList<Status>();
301

    
302
        // add context info
303
        List<String> contextInfo = getContextInfo();
304
        for(String infoItem : contextInfo) {
305
            childStatuses.add(new Status(IStatus.ERROR, pluginId, infoItem));
306
        }
307

    
308
        if(throwable == null) {
309
            throwable = getDefaultThrowable();
310
        }
311

    
312
        int thCount = 0;
313
        int maxTraces = 4;
314

    
315
        for(Throwable th : ExceptionUtils.getThrowables(throwable)) {
316
            // add main exception
317
            if(thCount == 0) {
318
                for (StackTraceElement ste : th.getStackTrace()) {
319
                    childStatuses.add(new Status(IStatus.ERROR, pluginId, "  at " + ste.toString()));
320
                }
321
            } else {
322
                // add recursive causes
323
                if(th != null) {
324
                    childStatuses.add(new Status(IStatus.ERROR, pluginId, ""));
325
                    String msg = th.toString();
326
                    childStatuses.add(new Status(IStatus.ERROR, pluginId, "Caused by : " + msg));
327
                    int traceCount = 0;
328
                    for (StackTraceElement ste : th.getStackTrace()) {
329
                        // add only pre-defined number of trace elements
330
                        if(traceCount > maxTraces) {
331
                            childStatuses.add(new Status(IStatus.ERROR, pluginId, "  ...."));
332
                            break;
333
                        }
334
                        // build & add status
335
                        childStatuses.add(new Status(IStatus.ERROR, pluginId, "  at " + ste.toString()));
336
                        traceCount++;
337
                    }
338
                }
339
            }
340
            thCount++;
341
        }
342
        String finalMessage = message;
343

    
344
        if(finalMessage == null || finalMessage.isEmpty()) {
345
            finalMessage = DEFAULT_MESSAGE;
346
        }
347

    
348
        if(addContactMesg) {
349
            // add edit support contact info to message
350
            finalMessage += MessagingUtils.CONTACT_MESSAGE;
351
        }
352

    
353
        MultiStatus ms = new MultiStatus(pluginId,
354
                IStatus.ERROR,
355
                childStatuses.toArray(new Status[] {}),
356
                throwable.toString(),
357
                throwable);
358

    
359
        errorDialog(title, source, throwable, contextInfo, finalMessage, ms);
360
    }
361

    
362
    /**
363
     * Displays a dialog for an exception occurring in an operation.
364
     *
365
     * This will be either a {@link eu.etaxonomy.taxeditor.model.CdmErrorDialog} in case of a
366
     * security runtime exception or a warning {@link org.eclipse.jface.dialogs.MessageDialog} in
367
     * case of any other exception.
368
     *
369
     * @param title
370
     *            a {@link java.lang.String} object.
371
     * @param source
372
     *            a {@link java.lang.Object} object.
373
     * @param status
374
     *            a {@link org.eclipse.core.runtime.IStatus} object.
375
     */
376
    public static void operationDialog(final Object source,
377
            final Exception ex,
378
            final String pluginId,
379
            final String operationlabel,
380
            final String hint) {
381

    
382
        Display.getDefault().asyncExec(new Runnable() {
383

    
384
            @Override
385
            public void run() {
386
                MultiStatus info = null;
387
                String title = null;
388

    
389
                // FIXME cannot access TaxonomicEditorPlugin.PLUGIN_ID from here
390
                // String PID = TaxonomicEditorPlugin.PLUGIN_ID;
391
                String PID = "eu.etaxonomy.taxeditor.application";
392

    
393
                // checking security exceptions for every operation
394
                RuntimeException securityRuntimeException = SecurityExceptionUtils.findSecurityRuntimeException(ex);
395

    
396
                // in case of a security exception it is a warning, else it is an error
397
                if(securityRuntimeException != null){
398
                    title = "Your changes could not be saved!";
399
                    warningDialog(title, source, String.format("You are missing sufficient permissions for the operation \"%s\". %s", operationlabel, hint));
400
                } else {
401
                    title = "Error executing operation";
402
                    errorDialog(title, source, String.format("An error occured while executing %s. %s", operationlabel, hint), pluginId, ex, true);
403

    
404
                }
405

    
406

    
407
            }
408
        });
409
    }
410

    
411

    
412

    
413

    
414
    /**
415
     * Displays a question {@link org.eclipse.jface.dialogs.MessageDialog}.
416
     *
417
     * @param title
418
     *            a {@link java.lang.String} object.
419
     * @param message
420
     *            a {@link java.lang.String} object.
421
     * @return a boolean.
422
     */
423
    public static boolean confirmDialog(String title, String message) {
424
        return MessageDialog.openQuestion(AbstractUtility.getShell(), title, message);
425
    }
426

    
427
    /**
428
     * Displays a message {@link org.eclipse.jface.dialogs.MessageDialog}.
429
     *
430
     * @param title
431
     * @param source
432
     * @param message
433
     */
434
    public static void messageDialog(final String title, final Object source, final String message) {
435
        MessagingUtils.messageDialog(title, source, message, null, true);
436
    }
437

    
438

    
439

    
440
    /**
441
     * Displays an error {@link org.eclipse.jface.dialogs.MessageDialog}.
442
     *
443
     * @param title
444
     *            The dialogs title
445
     * @param source
446
     *            The object where the warning was generated (used by log4j)
447
     * @param message
448
     *            An informative String to be presented to the user
449
     * @param title
450
     *            The dialogs title
451
     * @param t
452
     *            a Throwable if one exists or null
453
     */
454
    public static void messageDialog(final String title,
455
            final Object source,
456
            final String message,
457
            final Throwable t) {
458
        MessagingUtils.messageDialog(title, source, message, t, true);
459
    }
460

    
461
    /**
462
     * Displays an error {@link org.eclipse.jface.dialogs.MessageDialog}.
463
     *
464
     * @param title
465
     *            The dialogs title
466
     * @param source
467
     *            The object where the warning was generated (used by log4j)
468
     * @param message
469
     *            An informative String to be presented to the user
470
     * @param title
471
     *            The dialogs title
472
     * @param t
473
     *            a Throwable if one exists or null
474
     */
475
    public static void messageDialog(final String title,
476
            final Object source,
477
            final String message,
478
            final Throwable t,
479
            boolean async) {
480
        if(async) {
481
            Display.getDefault().asyncExec(new Runnable() {
482

    
483
                @Override
484
                public void run() {
485
                    MessageDialog.openError(AbstractUtility.getShell(), title, message + getCauseRecursively(t));
486
                    Class<? extends Object> clazz = source != null ? source
487
                            .getClass() : this.getClass();
488
                            error(clazz, message, t);
489
                }
490

    
491

    
492
            });
493
        } else {
494
            MessageDialog.openError(AbstractUtility.getShell(), title, message + getCauseRecursively(t));
495
            Class<? extends Object> clazz = source != null ? source.getClass() : TaxeditorStorePlugin.class;
496
            error(clazz, message, t);
497
        }
498
    }
499

    
500
    public static String getCauseRecursively(Throwable t) {
501
        if(t == null){
502
            return "";
503
        }
504

    
505
        if(t.getCause() != null){
506
            return getCauseRecursively(t.getCause());
507
        }else{
508
            return String.format("\n\nException: %s\nMessage: %s", t.getClass().getSimpleName(), t.getMessage());
509
        }
510

    
511
    }
512
    /**
513
     * Displays a warning {@link org.eclipse.jface.dialogs.MessageDialog}.
514
     *
515
     * @param title
516
     * @param termBase
517
     * @param status
518
     */
519
    public static void warningDialog(String title, Object source,
520
            IStatus status) {
521
        MessagingUtils.warningDialog(title, source, status.getMessage());
522
    }
523

    
524
    /**
525
     * Standard warning dialog for the case when the application is not yet connected to the datasource
526
     *
527
     * @param source
528
     */
529
    public static void noDataSourceWarningDialog(Object source) {
530
        MessagingUtils
531
        .warningDialog(
532
                "Application is not connected to a datastore",
533
                source,
534
                "The requested operation is only available when "
535
                + "connected to a datasource. You may choose a datasource to connect to or create a new one in the datasource view.");
536
    }
537

    
538
    /**
539
     * Displays a warning {@link org.eclipse.jface.dialogs.MessageDialog}.
540
     *
541
     * @param title
542
     *            The dialogs title
543
     * @param source
544
     *            The object where the warning was generated (used by log4j)
545
     * @param message
546
     *            An informative String to be presented to the user
547
     */
548
    public static void warningDialog(final String title, final Object source, final String message) {
549
        Display.getDefault().asyncExec(new Runnable() {
550

    
551
            @Override
552
            public void run() {
553
                MessageDialog.openWarning(AbstractUtility.getShell(), title, message);
554
                Class<? extends Object> clazz = source != null ? source
555
                        .getClass() : AbstractUtility.class;
556
                        warn(clazz, message);
557
            }
558
        });
559
    }
560

    
561
    /**
562
     * Displays an information {@link org.eclipse.jface.dialogs.MessageDialog}.
563
     *
564
     * @param title
565
     * @param status
566
     */
567
    public static void informationDialog(final String title, final IStatus status) {
568
        MessagingUtils.informationDialog(title, status.getMessage());
569
    }
570

    
571
    /**
572
     * Displays an information {@link org.eclipse.jface.dialogs.MessageDialog}.
573
     *
574
     * @param title
575
     *            a {@link java.lang.String} object.
576
     * @param message
577
     *            a {@link java.lang.String} object.
578
     */
579
    public static void informationDialog(final String title,
580
            final String message) {
581
        Display.getDefault().asyncExec(new Runnable() {
582

    
583
            @Override
584
            public void run() {
585
                MessageDialog.openInformation(AbstractUtility.getShell(), title, message);
586
            }
587
        });
588
    }
589

    
590
    /**
591
     * Open a message box that informs the user about unimplemented
592
     * functionality. This method is for developer convenience.
593
     *
594
     * @param source
595
     *            a {@link java.lang.Object} object.
596
     */
597
    public static void notImplementedMessage(Object source) {
598
        warningDialog("Not yet implemented", source,
599
                "This functionality is not yet implemented.");
600
    }
601

    
602
}
(30-30/39)