Project

General

Profile

Download (21.4 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.common.CdmUtils;
18
import eu.etaxonomy.cdm.config.ICdmSource;
19
import eu.etaxonomy.cdm.test.integration.SecurityExceptionUtils;
20
import eu.etaxonomy.taxeditor.remoting.source.CdmRemoteSource;
21
import eu.etaxonomy.taxeditor.store.CdmStore;
22
import eu.etaxonomy.taxeditor.store.internal.TaxeditorStorePlugin;
23

    
24
/**
25
 * Utility class which handles all the messaging information generated by the
26
 * Editor.
27
 *
28
 * This includes logging as well as dialogs.
29
 *
30
 * @author cmathew
31
 *
32
 */
33
public class MessagingUtils {
34
    public final static String UNEXPECTED_ERROR_MESSAGE = "This is an unexpected error.";
35
    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).";
36
    public final static String DEFAULT_MESSAGE = "Error thrown but no associated message";
37
    public final static String CONNECTION_FAILURE_MESSAGE = "The connection to the remote server has been broken";
38
    public final static String REMOTE_ACCESS_FAILURE_MESSAGE = "Maybe the server is currently not available. If the problem persists please contact the server admin with the error trace below.";
39
    public static final String WIDGET_IS_DISPOSED_MESSAGE = "A widget was called, which was already disposed";
40

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

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

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

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

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

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

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

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

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

    
152

    
153

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

    
167

    
168

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

    
189
            ICdmSource activeCdmSource = CdmStore.getActiveCdmSource();
190
            if(activeCdmSource != null ) {
191
                login = CdmStore.getLoginManager().getAuthenticatedUser().getUsername();
192
                name = activeCdmSource.getName();
193
                schemaVersion = activeCdmSource.getDbSchemaVersion();
194
                server = activeCdmSource.getServer();
195
                if(activeCdmSource instanceof CdmRemoteSource){
196
                    contextPath = ((CdmRemoteSource) activeCdmSource).getContextPath();
197
                    if (contextPath != null && contextPath.startsWith("cdmserver/")){
198
                    	contextPath = contextPath.substring("cdmserver/".length());
199
                    }
200
                }
201
            }
202

    
203
        } catch (Exception e) {
204
            // Nothing to do
205
        }
206
        contextInfo.add("login : " + login);
207
        contextInfo.add("editor version : " + version);
208
        contextInfo.add("server : " + server + " (" + name + ")" + (CdmUtils.isNotBlank(contextPath)?" / "+contextPath:""));
209
        contextInfo.add("schema version : " + schemaVersion);
210
        contextInfo.add("os : " + System.getProperty("os.name")+" "+System.getProperty("os.version")+" "+System.getProperty("os.arch"));
211
        contextInfo.add("java : "+System.getProperty("java.version"));
212

    
213
        return contextInfo;
214
    }
215

    
216
    public static String getStackTraceAndContextInfo(Throwable t, List<String> contextInfo)  {
217
        StringBuffer stackTraceAndContextInfo = new StringBuffer();
218
        Throwable throwable = t;
219

    
220
        for(String infoItem : contextInfo) {
221
            stackTraceAndContextInfo.append(infoItem + System.getProperty("line.separator"));
222
        }
223

    
224
        StringWriter sw = new StringWriter();
225

    
226
        if(throwable == null) {
227
            throwable = getDefaultThrowable();
228
        }
229
        throwable.printStackTrace(new PrintWriter(sw));
230

    
231
        stackTraceAndContextInfo.append(sw.toString());
232

    
233
        return stackTraceAndContextInfo.toString();
234
    }
235

    
236
    public static String getContextInfo(List<String> contextInfo)  {
237
        StringBuffer scontextInfoStringBuffer = new StringBuffer();
238

    
239

    
240
        for(String infoItem : contextInfo) {
241
            scontextInfoStringBuffer.append(infoItem + System.getProperty("line.separator"));
242
        }
243

    
244

    
245

    
246
        return scontextInfoStringBuffer.toString();
247
    }
248

    
249
    private static Throwable getDefaultThrowable() {
250
        return new Throwable("Error thrown but no associated exception");
251
    }
252

    
253

    
254

    
255
    /**
256
     * Displays a {@link eu.etaxonomy.taxeditor.model.CdmErrorDialog}.
257
     *
258
     * @param title
259
     * @param source
260
     * @param t
261
     * @param contextInfo
262
     * @param message
263
     * @param status
264
     */
265
    private static void errorDialog(final String title,
266
            final Object source,
267
            final Throwable t,
268
            final List<String> contextInfo,
269
            final String message,
270
            final MultiStatus status,
271
            final boolean showReason) {
272

    
273
        Display.getDefault().asyncExec(new Runnable() {
274

    
275
            @Override
276
            public void run() {
277
                String stackTraceWithContext = getStackTraceAndContextInfo(t, contextInfo);
278
                CdmErrorDialog ced = new CdmErrorDialog(AbstractUtility.getShell(), title, message, status, stackTraceWithContext, showReason);
279
                ced.open();
280
                Class<? extends Object> clazz = source != null ? source.getClass() : this.getClass();
281

    
282

    
283
                IStatus singleStatus = new Status(IStatus.ERROR,
284
                        status.getPlugin(),
285
                        message,
286
                        new Exception(stackTraceWithContext));
287

    
288
                error(clazz, singleStatus);
289
            }
290
        });
291
    }
292

    
293
    public static void errorDialog(final String title,
294
            final Object source,
295
            final String message,
296
            final String pluginId,
297
            final Throwable t,
298
            boolean addContactMesg) {
299
        errorDialog(title, source, message, pluginId, t, addContactMesg, true);
300

    
301
    }
302
    /**
303
     * Displays a {@link eu.etaxonomy.taxeditor.model.CdmErrorDialog}.
304
     *
305
     * @param title
306
     * @param source
307
     * @param message
308
     * @param pluginId
309
     * @param t
310
     */
311
    public static void errorDialog(final String title,
312
            final Object source,
313
            final String message,
314
            final String pluginId,
315
            final Throwable t,
316
            boolean addContactMesg,
317
            boolean showReason) {
318

    
319
        Throwable throwable = t;
320
        StringBuffer sbStackTrace = new StringBuffer();
321

    
322
        // We need to build a MultiStatus object since the simple
323
        // idea of writing out the stack trace as a single string
324
        // leads to a single line on windows
325
        List<Status> childStatuses = new ArrayList<Status>();
326

    
327
        // add context info
328
        List<String> contextInfo = getContextInfo();
329
        for(String infoItem : contextInfo) {
330
            childStatuses.add(new Status(IStatus.ERROR, pluginId, infoItem));
331
        }
332

    
333
        if(throwable == null) {
334
            throwable = getDefaultThrowable();
335
        }
336

    
337
        int thCount = 0;
338
        int maxTraces = 4;
339

    
340
        for(Throwable th : ExceptionUtils.getThrowables(throwable)) {
341
            // add main exception
342
            if(thCount == 0) {
343
                for (StackTraceElement ste : th.getStackTrace()) {
344
                    childStatuses.add(new Status(IStatus.ERROR, pluginId, "  at " + ste.toString()));
345
                }
346
            } else {
347
                // add recursive causes
348
                if(th != null) {
349
                    childStatuses.add(new Status(IStatus.ERROR, pluginId, ""));
350
                    String msg = th.toString();
351
                    childStatuses.add(new Status(IStatus.ERROR, pluginId, "Caused by : " + msg));
352
                    int traceCount = 0;
353
                    for (StackTraceElement ste : th.getStackTrace()) {
354
                        // add only pre-defined number of trace elements
355
                        if(traceCount > maxTraces) {
356
                            childStatuses.add(new Status(IStatus.ERROR, pluginId, "  ...."));
357
                            break;
358
                        }
359
                        // build & add status
360
                        childStatuses.add(new Status(IStatus.ERROR, pluginId, "  at " + ste.toString()));
361
                        traceCount++;
362
                    }
363
                }
364
            }
365
            thCount++;
366
        }
367
        String finalMessage = message;
368

    
369
        if(finalMessage == null || finalMessage.isEmpty()) {
370
            finalMessage = DEFAULT_MESSAGE;
371
        }
372

    
373
        if(addContactMesg) {
374
            // add edit support contact info to message
375
            finalMessage += MessagingUtils.CONTACT_MESSAGE;
376
        }
377

    
378
        MultiStatus ms = new MultiStatus(pluginId,
379
                IStatus.ERROR,
380
                childStatuses.toArray(new Status[] {}),
381
                throwable.toString(),
382
                throwable);
383

    
384
        errorDialog(title, source, throwable, contextInfo, finalMessage, ms, showReason);
385
    }
386

    
387
    /**
388
     * Displays a dialog for an exception occurring in an operation.
389
     *
390
     * This will be either a {@link eu.etaxonomy.taxeditor.model.CdmErrorDialog} in case of a
391
     * security runtime exception or a warning {@link org.eclipse.jface.dialogs.MessageDialog} in
392
     * case of any other exception.
393
     *
394
     * @param title
395
     *            a {@link java.lang.String} object.
396
     * @param source
397
     *            a {@link java.lang.Object} object.
398
     * @param status
399
     *            a {@link org.eclipse.core.runtime.IStatus} object.
400
     */
401
    public static void operationDialog(final Object source,
402
            final Exception ex,
403
            final String pluginId,
404
            final String operationlabel,
405
            final String hint) {
406

    
407
        Display.getDefault().asyncExec(new Runnable() {
408

    
409
            @Override
410
            public void run() {
411
                MultiStatus info = null;
412
                String title = null;
413

    
414
                // FIXME cannot access TaxonomicEditorPlugin.PLUGIN_ID from here
415
                // String PID = TaxonomicEditorPlugin.PLUGIN_ID;
416
                String PID = "eu.etaxonomy.taxeditor.application";
417

    
418
                // checking security exceptions for every operation
419
                RuntimeException securityRuntimeException = SecurityExceptionUtils.findSecurityRuntimeException(ex);
420

    
421
                // in case of a security exception it is a warning, else it is an error
422
                if(securityRuntimeException != null){
423
                    title = "Your changes could not be saved!";
424
                    warningDialog(title, source, String.format("You are missing sufficient permissions for the operation \"%s\". %s", operationlabel, hint));
425
                } else {
426
                    title = "Error executing operation";
427
                    errorDialog(title, source, String.format("An error occured while executing %s. %s", operationlabel, hint), pluginId, ex, true);
428

    
429
                }
430

    
431

    
432
            }
433
        });
434
    }
435

    
436

    
437

    
438

    
439
    /**
440
     * Displays a question {@link org.eclipse.jface.dialogs.MessageDialog}.
441
     *
442
     * @param title
443
     *            a {@link java.lang.String} object.
444
     * @param message
445
     *            a {@link java.lang.String} object.
446
     * @return a boolean.
447
     */
448
    public static boolean confirmDialog(String title, String message) {
449
        return MessageDialog.openQuestion(AbstractUtility.getShell(), title, message);
450
    }
451

    
452
    /**
453
     * Displays a message {@link org.eclipse.jface.dialogs.MessageDialog}.
454
     *
455
     * @param title
456
     * @param source
457
     * @param message
458
     */
459
    public static void messageDialog(final String title, final Object source, final String message) {
460
        MessagingUtils.messageDialog(title, source, message, null, true);
461
    }
462

    
463

    
464

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

    
486
    /**
487
     * Displays an error {@link org.eclipse.jface.dialogs.MessageDialog}.
488
     *
489
     * @param title
490
     *            The dialogs title
491
     * @param source
492
     *            The object where the warning was generated (used by log4j)
493
     * @param message
494
     *            An informative String to be presented to the user
495
     * @param title
496
     *            The dialogs title
497
     * @param t
498
     *            a Throwable if one exists or null
499
     */
500
    public static void messageDialog(final String title,
501
            final Object source,
502
            final String message,
503
            final Throwable t,
504
            boolean async) {
505
        if(async) {
506
            Display.getDefault().asyncExec(new Runnable() {
507

    
508
                @Override
509
                public void run() {
510
                    MessageDialog.openError(AbstractUtility.getShell(), title, message + getCauseRecursively(t));
511
                    Class<? extends Object> clazz = source != null ? source
512
                            .getClass() : this.getClass();
513
                            error(clazz, message, t);
514
                }
515

    
516

    
517
            });
518
        } else {
519
            MessageDialog.openError(AbstractUtility.getShell(), title, message + getCauseRecursively(t));
520
            Class<? extends Object> clazz = source != null ? source.getClass() : TaxeditorStorePlugin.class;
521
            error(clazz, message, t);
522
        }
523
    }
524

    
525
    public static String getCauseRecursively(Throwable t) {
526
        if(t == null){
527
            return "";
528
        }
529

    
530
        if(t.getCause() != null){
531
            return getCauseRecursively(t.getCause());
532
        }else{
533
            return String.format("\n\nException: %s\nMessage: %s", t.getClass().getSimpleName(), t.getMessage());
534
        }
535

    
536
    }
537
    /**
538
     * Displays a warning {@link org.eclipse.jface.dialogs.MessageDialog}.
539
     *
540
     * @param title
541
     * @param termBase
542
     * @param status
543
     */
544
    public static void warningDialog(String title, Object source,
545
            IStatus status) {
546
        MessagingUtils.warningDialog(title, source, status.getMessage());
547
    }
548

    
549
    /**
550
     * Standard warning dialog for the case when the application is not yet connected to the datasource
551
     *
552
     * @param source
553
     */
554
    public static void noDataSourceWarningDialog(Object source) {
555
        MessagingUtils
556
        .warningDialog(
557
                "Application is not connected to a datastore",
558
                source,
559
                "The requested operation is only available when "
560
                + "connected to a datasource. You may choose a datasource to connect to or create a new one in the datasource view.");
561
    }
562

    
563
    /**
564
     * Standard warning dialog for the case when the datasource is not available
565
     *
566
     * @param source
567
     */
568
    public static void dataSourceNotAvailableWarningDialog(Object source) {
569
        MessagingUtils
570
        .warningDialog(
571
                "The datasource is not available",
572
                source,
573
                "The editor is not connected to a datasource. Maybe the datasource is not available.");
574
    }
575

    
576

    
577
    /**
578
     * Displays a warning {@link org.eclipse.jface.dialogs.MessageDialog}.
579
     *
580
     * @param title
581
     *            The dialogs title
582
     * @param source
583
     *            The object where the warning was generated (used by log4j)
584
     * @param message
585
     *            An informative String to be presented to the user
586
     */
587
    public static void warningDialog(final String title, final Object source, final String message) {
588
        Display.getDefault().asyncExec(new Runnable() {
589

    
590
            @Override
591
            public void run() {
592
                MessageDialog.openWarning(AbstractUtility.getShell(), title, message);
593
                Class<? extends Object> clazz = source != null ? source
594
                        .getClass() : AbstractUtility.class;
595
                        warn(clazz, message);
596
            }
597
        });
598
    }
599

    
600
    /**
601
     * Displays an information {@link org.eclipse.jface.dialogs.MessageDialog}.
602
     *
603
     * @param title
604
     * @param status
605
     */
606
    public static void informationDialog(final String title, final IStatus status) {
607
        MessagingUtils.informationDialog(title, status.getMessage());
608
    }
609

    
610
    /**
611
     * Displays an information {@link org.eclipse.jface.dialogs.MessageDialog}.
612
     *
613
     * @param title
614
     *            a {@link java.lang.String} object.
615
     * @param message
616
     *            a {@link java.lang.String} object.
617
     */
618
    public static void informationDialog(final String title,
619
            final String message) {
620
        Display.getDefault().asyncExec(new Runnable() {
621

    
622
            @Override
623
            public void run() {
624
                MessageDialog.openInformation(AbstractUtility.getShell(), title, message);
625
            }
626
        });
627
    }
628

    
629
    /**
630
     * Open a message box that informs the user about unimplemented
631
     * functionality. This method is for developer convenience.
632
     *
633
     * @param source
634
     *            a {@link java.lang.Object} object.
635
     */
636
    public static void notImplementedMessage(Object source) {
637
        warningDialog("Not yet implemented", source,
638
                "This functionality is not yet implemented.");
639
    }
640

    
641
}
(29-29/38)