Project

General

Profile

Download (18.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.log4j.Logger;
9
import org.eclipse.core.runtime.IStatus;
10
import org.eclipse.core.runtime.MultiStatus;
11
import org.eclipse.core.runtime.Platform;
12
import org.eclipse.core.runtime.Status;
13
import org.eclipse.jface.dialogs.MessageDialog;
14
import org.eclipse.swt.widgets.Display;
15

    
16
import eu.etaxonomy.cdm.persistence.hibernate.permission.SecurityExceptionUtils;
17
import eu.etaxonomy.taxeditor.store.CdmStore;
18
import eu.etaxonomy.taxeditor.store.internal.TaxeditorStorePlugin;
19

    
20
/**
21
 * Utility class which handles all the messaging information generated by the
22
 * Editor.
23
 *
24
 * This includes logging as well as dialogs.
25
 *
26
 * @author cmathew
27
 *
28
 */
29
public class MessagingUtils {
30
    public final static String UNEXPECTED_ERROR_MESSAGE = "This is an unexpected error.";
31
    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).";
32
    public final static String DEFAULT_MESSAGE = "Error thrown but no associated message";
33

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

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

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

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

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

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

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

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

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

    
145

    
146

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

    
160

    
161

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

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

    
188
        } catch (Exception e) {
189
            // Nothing to do
190
        }
191
        contextInfo.add("login : " + login);
192
        contextInfo.add("editor version : " + version);
193
        contextInfo.add("server : " + server + " / " + name);
194
        contextInfo.add("schema version : " + schemaVersion);
195

    
196
        return contextInfo;
197
    }
198

    
199
    public static String getStackTraceAndContextInfo(Throwable t, List<String> contextInfo)  {
200
        StringBuffer stackTraceAndContextInfo = new StringBuffer();
201
        Throwable throwable = t;
202

    
203
        for(String infoItem : contextInfo) {
204
            stackTraceAndContextInfo.append(infoItem + System.getProperty("line.separator"));
205
        }
206

    
207
        StringWriter sw = new StringWriter();
208

    
209
        if(throwable == null) {
210
            throwable = getDefaultThrowable();
211
        }
212
        throwable.printStackTrace(new PrintWriter(sw));
213

    
214
        stackTraceAndContextInfo.append(sw.toString());
215

    
216
        return stackTraceAndContextInfo.toString();
217
    }
218

    
219
    private static Throwable getDefaultThrowable() {
220
        return new Throwable("Error thrown but no associated exception");
221
    }
222

    
223

    
224

    
225
    /**
226
     * Displays a {@link eu.etaxonomy.taxeditor.model.CdmErrorDialog}.
227
     *
228
     * @param title
229
     * @param source
230
     * @param t
231
     * @param contextInfo
232
     * @param message
233
     * @param status
234
     */
235
    private static void errorDialog(final String title,
236
            final Object source,
237
            final Throwable t,
238
            final List<String> contextInfo,
239
            final String message,
240
            final MultiStatus status) {
241

    
242
        Display.getDefault().asyncExec(new Runnable() {
243

    
244
            @Override
245
            public void run() {
246
                String stackTraceWithContext = getStackTraceAndContextInfo(t, contextInfo);
247
                CdmErrorDialog ced = new CdmErrorDialog(AbstractUtility.getShell(), title, message, status, stackTraceWithContext);
248
                ced.open();
249
                Class<? extends Object> clazz = source != null ? source.getClass() : this.getClass();
250

    
251

    
252
                IStatus singleStatus = new Status(IStatus.ERROR,
253
                        status.getPlugin(),
254
                        message,
255
                        new Exception(stackTraceWithContext));
256

    
257
                error(clazz, singleStatus);
258
            }
259
        });
260
    }
261

    
262
    /**
263
     * Displays a {@link eu.etaxonomy.taxeditor.model.CdmErrorDialog}.
264
     *
265
     * @param title
266
     * @param source
267
     * @param message
268
     * @param pluginId
269
     * @param t
270
     */
271
    public static void errorDialog(final String title,
272
            final Object source,
273
            final String message,
274
            final String pluginId,
275
            final Throwable t,
276
            boolean addContactMesg) {
277

    
278
        Throwable throwable = t;
279
        StringBuffer sbStackTrace = new StringBuffer();
280

    
281
        // We need to build a MultiStatus object since the simple
282
        // idea of writing out the stack trace as a single string
283
        // leads to a single line on windows
284
        List<Status> childStatuses = new ArrayList<Status>();
285

    
286
        // add context info
287
        List<String> contextInfo = getContextInfo();
288
        for(String infoItem : contextInfo) {
289
            childStatuses.add(new Status(IStatus.ERROR, pluginId, infoItem));
290
        }
291

    
292
        if(throwable == null) {
293
            throwable = getDefaultThrowable();
294
        }
295

    
296
        // add main execption
297
        for (StackTraceElement ste : throwable.getStackTrace()) {
298
            childStatuses.add(new Status(IStatus.ERROR, pluginId, "at " + ste.toString()));
299
        }
300

    
301
        // add cause
302
        if(throwable.getCause() != null) {
303
            childStatuses.add(new Status(IStatus.ERROR, pluginId, ""));
304
            childStatuses.add(new Status(IStatus.ERROR, pluginId, "Caused by : " + throwable.getCause().toString()));
305
            for (StackTraceElement ste : throwable.getCause().getStackTrace()) {
306
                // build & add status
307
                childStatuses.add(new Status(IStatus.ERROR, pluginId, "at " + ste.toString()));
308
            }
309
        }
310

    
311
        String finalMessage = message;
312

    
313
        if(finalMessage == null || finalMessage.isEmpty()) {
314
            finalMessage = DEFAULT_MESSAGE;
315
        }
316

    
317
        if(addContactMesg) {
318
            // add edit support contact info to message
319
            finalMessage += MessagingUtils.CONTACT_MESSAGE;
320
        }
321

    
322
        MultiStatus ms = new MultiStatus(pluginId,
323
                IStatus.ERROR,
324
                childStatuses.toArray(new Status[] {}),
325
                throwable.toString(),
326
                throwable);
327

    
328
        errorDialog(title, source, throwable, contextInfo, finalMessage, ms);
329
    }
330

    
331
    /**
332
     * Displays a dialog for an exception occurring in an operation.
333
     *
334
     * This will be either a {@link eu.etaxonomy.taxeditor.model.CdmErrorDialog} in case of a
335
     * security runtime exception or a warning {@link org.eclipse.jface.dialogs.MessageDialog} in
336
     * case of any other exception.
337
     *
338
     * @param title
339
     *            a {@link java.lang.String} object.
340
     * @param source
341
     *            a {@link java.lang.Object} object.
342
     * @param status
343
     *            a {@link org.eclipse.core.runtime.IStatus} object.
344
     */
345
    public static void operationDialog(final Object source,
346
            final Exception ex,
347
            final String pluginId,
348
            final String operationlabel,
349
            final String hint) {
350

    
351
        Display.getDefault().asyncExec(new Runnable() {
352

    
353
            @Override
354
            public void run() {
355
                MultiStatus info = null;
356
                String title = null;
357

    
358
                // FIXME cannot access TaxonomicEditorPlugin.PLUGIN_ID from here
359
                // String PID = TaxonomicEditorPlugin.PLUGIN_ID;
360
                String PID = "eu.etaxonomy.taxeditor.application";
361

    
362
                // checking security exceptions for every operation
363
                RuntimeException securityRuntimeException = SecurityExceptionUtils.findSecurityRuntimeException(ex);
364

    
365
                // in case of a security exception it is a warning, else it is an error
366
                if(securityRuntimeException != null){
367
                    title = "Your changes could not be saved!";
368
                    warningDialog(title, source, String.format("You are missing sufficient permissions for the operation \"%s\". %s", operationlabel, hint));
369
                } else {
370
                    title = "Error executing operation";
371
                    errorDialog(title, source, String.format("An error occured while executing %s. %s", operationlabel, hint), pluginId, ex, true);
372

    
373
                }
374

    
375

    
376
            }
377
        });
378
    }
379

    
380

    
381

    
382

    
383
    /**
384
     * Displays a question {@link org.eclipse.jface.dialogs.MessageDialog}.
385
     *
386
     * @param title
387
     *            a {@link java.lang.String} object.
388
     * @param message
389
     *            a {@link java.lang.String} object.
390
     * @return a boolean.
391
     */
392
    public static boolean confirmDialog(String title, String message) {
393
        return MessageDialog.openQuestion(AbstractUtility.getShell(), title, message);
394
    }
395

    
396
    /**
397
     * Displays a message {@link org.eclipse.jface.dialogs.MessageDialog}.
398
     *
399
     * @param title
400
     * @param source
401
     * @param message
402
     */
403
    public static void messageDialog(final String title, final Object source, final String message) {
404
        MessagingUtils.messageDialog(title, source, message, null, true);
405
    }
406

    
407

    
408

    
409
    /**
410
     * Displays an error {@link org.eclipse.jface.dialogs.MessageDialog}.
411
     *
412
     * @param title
413
     *            The dialogs title
414
     * @param source
415
     *            The object where the warning was generated (used by log4j)
416
     * @param message
417
     *            An informative String to be presented to the user
418
     * @param title
419
     *            The dialogs title
420
     * @param t
421
     *            a Throwable if one exists or null
422
     */
423
    public static void messageDialog(final String title,
424
            final Object source,
425
            final String message,
426
            final Throwable t) {
427
        MessagingUtils.messageDialog(title, source, message, t, true);
428
    }
429

    
430
    /**
431
     * Displays an error {@link org.eclipse.jface.dialogs.MessageDialog}.
432
     *
433
     * @param title
434
     *            The dialogs title
435
     * @param source
436
     *            The object where the warning was generated (used by log4j)
437
     * @param message
438
     *            An informative String to be presented to the user
439
     * @param title
440
     *            The dialogs title
441
     * @param t
442
     *            a Throwable if one exists or null
443
     */
444
    public static void messageDialog(final String title,
445
            final Object source,
446
            final String message,
447
            final Throwable t,
448
            boolean async) {
449
        if(async) {
450
            Display.getDefault().asyncExec(new Runnable() {
451

    
452
                @Override
453
                public void run() {
454
                    MessageDialog.openError(AbstractUtility.getShell(), title, message + getCauseRecursively(t));
455
                    Class<? extends Object> clazz = source != null ? source
456
                            .getClass() : this.getClass();
457
                            error(clazz, message, t);
458
                }
459

    
460

    
461
            });
462
        } else {
463
            MessageDialog.openError(AbstractUtility.getShell(), title, message + getCauseRecursively(t));
464
            Class<? extends Object> clazz = source != null ? source.getClass() : TaxeditorStorePlugin.class;
465
            error(clazz, message, t);
466
        }
467
    }
468

    
469
    public static String getCauseRecursively(Throwable t) {
470
        if(t == null){
471
            return "";
472
        }
473

    
474
        if(t.getCause() != null){
475
            return getCauseRecursively(t.getCause());
476
        }else{
477
            return String.format("\n\nException: %s\nMessage: %s", t.getClass().getSimpleName(), t.getMessage());
478
        }
479

    
480
    }
481
    /**
482
     * Displays a warning {@link org.eclipse.jface.dialogs.MessageDialog}.
483
     *
484
     * @param title
485
     * @param termBase
486
     * @param status
487
     */
488
    public static void warningDialog(String title, Object source,
489
            IStatus status) {
490
        MessagingUtils.warningDialog(title, source, status.getMessage());
491
    }
492

    
493
    /**
494
     * Standard warning dialog for the case when the application is not yet connected to the datasource
495
     *
496
     * @param source
497
     */
498
    public static void noDataSourceWarningDialog(Object source) {
499
        MessagingUtils
500
        .warningDialog(
501
                "Application is not connected to a datastore",
502
                source,
503
                "The requested operation is only available when "
504
                + "connected to a datasource. You may choose a datasource to connect to or create a new one in the datasource view.");
505
    }
506

    
507
    /**
508
     * Displays a warning {@link org.eclipse.jface.dialogs.MessageDialog}.
509
     *
510
     * @param title
511
     *            The dialogs title
512
     * @param source
513
     *            The object where the warning was generated (used by log4j)
514
     * @param message
515
     *            An informative String to be presented to the user
516
     */
517
    public static void warningDialog(final String title, final Object source, final String message) {
518
        Display.getDefault().asyncExec(new Runnable() {
519

    
520
            @Override
521
            public void run() {
522
                MessageDialog.openWarning(AbstractUtility.getShell(), title, message);
523
                Class<? extends Object> clazz = source != null ? source
524
                        .getClass() : AbstractUtility.class;
525
                        warn(clazz, message);
526
            }
527
        });
528
    }
529

    
530
    /**
531
     * Displays an information {@link org.eclipse.jface.dialogs.MessageDialog}.
532
     *
533
     * @param title
534
     * @param status
535
     */
536
    public static void informationDialog(final String title, final IStatus status) {
537
        MessagingUtils.informationDialog(title, status.getMessage());
538
    }
539

    
540
    /**
541
     * Displays an information {@link org.eclipse.jface.dialogs.MessageDialog}.
542
     *
543
     * @param title
544
     *            a {@link java.lang.String} object.
545
     * @param message
546
     *            a {@link java.lang.String} object.
547
     */
548
    public static void informationDialog(final String title,
549
            final String message) {
550
        Display.getDefault().asyncExec(new Runnable() {
551

    
552
            @Override
553
            public void run() {
554
                MessageDialog.openInformation(AbstractUtility.getShell(), title, message);
555
            }
556
        });
557
    }
558

    
559
    /**
560
     * Open a message box that informs the user about unimplemented
561
     * functionality. This method is for developer convenience.
562
     *
563
     * @param source
564
     *            a {@link java.lang.Object} object.
565
     */
566
    public static void notImplementedMessage(Object source) {
567
        warningDialog("Not yet implemented", source,
568
                "This functionality is not yet implemented.");
569
    }
570

    
571
}
(28-28/37)