1 package eu
.etaxonomy
.taxeditor
.model
;
3 import java
.io
.PrintWriter
;
4 import java
.io
.StringWriter
;
5 import java
.util
.ArrayList
;
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
;
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
;
25 * Utility class which handles all the messaging information generated by the
28 * This includes logging as well as dialogs.
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";
42 * Gets the Log4J logger for a given class
45 * a {@link java.lang.Class} object.
46 * @return a {@link org.apache.log4j.Logger} object.
48 public static Logger
getLog4JLogger(Class clazz
) {
49 return Logger
.getLogger(clazz
);
53 * Logs details from a given Status object
56 * a {@link org.eclipse.core.runtime.IStatus} object.
58 private static void log(IStatus status
) {
59 TaxeditorStorePlugin
.getDefault().getLog().log(status
);
63 * Logs a status object as information.
66 * a {@link org.eclipse.core.runtime.IStatus} object.
68 public static void info(IStatus status
) {
73 * Logs a string as information.
76 * a {@link java.lang.String} object.
78 public static void info(String message
) {
79 IStatus status
= new Status(IStatus
.INFO
, AbstractUtility
.getPluginId(), message
);
84 * Logs an exception from a given source as a warning.
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
);
96 * Logs a status object from a given source as a warning.
101 public static void warn(Class source
, IStatus status
) {
102 MessagingUtils
.getLog4JLogger(source
).warn(status
.getMessage(), status
.getException());
107 * Logs a string from a given source as a warning.
111 * a {@link java.lang.Class} object.
113 * a {@link java.lang.String} object.
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
);
122 * Logs a status object from a given source as an error.
126 * a {@link java.lang.Class} object.
128 * a {@link org.eclipse.core.runtime.IStatus} object.
130 public static void error(Class source
, IStatus status
) {
131 getLog4JLogger(source
)
132 .error(status
.getMessage(), status
.getException());
137 * Logs a string and exception from a given source as an error.
141 * a {@link java.lang.Class} object.
143 * a {@link java.lang.String} object.
145 * a {@link java.lang.Throwable} object.
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
);
155 * Logs an exception from a given source as an error.
159 * a {@link java.lang.Class} object.
161 * a {@link java.lang.Throwable} object.
163 public static void error(Class source
, Throwable t
) {
164 error(source
.getClass(), t
.getMessage(), t
);
170 * Returns a list of strings, providing info on,
173 * - server (address + source name)
174 * - db schema version
178 public static List
<String
> getContextInfo() {
179 List
<String
> contextInfo
= new ArrayList
<String
>();
181 String contextPath
= "";
182 String schemaVersion
= "";
187 version
= Platform
.getBundle("eu.etaxonomy.taxeditor.application").getHeaders().get(org
.osgi
.framework
.Constants
.BUNDLE_VERSION
);
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();
200 } catch (Exception e
) {
203 contextInfo
.add("login : " + login
);
204 contextInfo
.add("editor version : " + version
);
205 contextInfo
.add("server : " + server
+ " / " + name
+ (CdmUtils
.isNotBlank(contextPath
)?
" / "+contextPath
:""));
206 contextInfo
.add("schema version : " + schemaVersion
);
207 contextInfo
.add("os : " + System
.getProperty("os.name")+" "+System
.getProperty("os.version")+" "+System
.getProperty("os.arch"));
208 contextInfo
.add("java : "+System
.getProperty("java.version"));
213 public static String
getStackTraceAndContextInfo(Throwable t
, List
<String
> contextInfo
) {
214 StringBuffer stackTraceAndContextInfo
= new StringBuffer();
215 Throwable throwable
= t
;
217 for(String infoItem
: contextInfo
) {
218 stackTraceAndContextInfo
.append(infoItem
+ System
.getProperty("line.separator"));
221 StringWriter sw
= new StringWriter();
223 if(throwable
== null) {
224 throwable
= getDefaultThrowable();
226 throwable
.printStackTrace(new PrintWriter(sw
));
228 stackTraceAndContextInfo
.append(sw
.toString());
230 return stackTraceAndContextInfo
.toString();
233 public static String
getContextInfo(List
<String
> contextInfo
) {
234 StringBuffer scontextInfoStringBuffer
= new StringBuffer();
237 for(String infoItem
: contextInfo
) {
238 scontextInfoStringBuffer
.append(infoItem
+ System
.getProperty("line.separator"));
243 return scontextInfoStringBuffer
.toString();
246 private static Throwable
getDefaultThrowable() {
247 return new Throwable("Error thrown but no associated exception");
253 * Displays a {@link eu.etaxonomy.taxeditor.model.CdmErrorDialog}.
262 private static void errorDialog(final String title
,
265 final List
<String
> contextInfo
,
266 final String message
,
267 final MultiStatus status
,
268 final boolean showReason
) {
270 Display
.getDefault().asyncExec(new Runnable() {
274 String stackTraceWithContext
= getStackTraceAndContextInfo(t
, contextInfo
);
275 CdmErrorDialog ced
= new CdmErrorDialog(AbstractUtility
.getShell(), title
, message
, status
, stackTraceWithContext
, showReason
);
277 Class
<?
extends Object
> clazz
= source
!= null ? source
.getClass() : this.getClass();
280 IStatus singleStatus
= new Status(IStatus
.ERROR
,
283 new Exception(stackTraceWithContext
));
285 error(clazz
, singleStatus
);
290 public static void errorDialog(final String title
,
292 final String message
,
293 final String pluginId
,
295 boolean addContactMesg
) {
296 errorDialog(title
, source
, message
, pluginId
, t
, addContactMesg
, true);
300 * Displays a {@link eu.etaxonomy.taxeditor.model.CdmErrorDialog}.
308 public static void errorDialog(final String title
,
310 final String message
,
311 final String pluginId
,
313 boolean addContactMesg
,
314 boolean showReason
) {
316 Throwable throwable
= t
;
317 StringBuffer sbStackTrace
= new StringBuffer();
319 // We need to build a MultiStatus object since the simple
320 // idea of writing out the stack trace as a single string
321 // leads to a single line on windows
322 List
<Status
> childStatuses
= new ArrayList
<Status
>();
325 List
<String
> contextInfo
= getContextInfo();
326 for(String infoItem
: contextInfo
) {
327 childStatuses
.add(new Status(IStatus
.ERROR
, pluginId
, infoItem
));
330 if(throwable
== null) {
331 throwable
= getDefaultThrowable();
337 for(Throwable th
: ExceptionUtils
.getThrowables(throwable
)) {
338 // add main exception
340 for (StackTraceElement ste
: th
.getStackTrace()) {
341 childStatuses
.add(new Status(IStatus
.ERROR
, pluginId
, " at " + ste
.toString()));
344 // add recursive causes
346 childStatuses
.add(new Status(IStatus
.ERROR
, pluginId
, ""));
347 String msg
= th
.toString();
348 childStatuses
.add(new Status(IStatus
.ERROR
, pluginId
, "Caused by : " + msg
));
350 for (StackTraceElement ste
: th
.getStackTrace()) {
351 // add only pre-defined number of trace elements
352 if(traceCount
> maxTraces
) {
353 childStatuses
.add(new Status(IStatus
.ERROR
, pluginId
, " ...."));
356 // build & add status
357 childStatuses
.add(new Status(IStatus
.ERROR
, pluginId
, " at " + ste
.toString()));
364 String finalMessage
= message
;
366 if(finalMessage
== null || finalMessage
.isEmpty()) {
367 finalMessage
= DEFAULT_MESSAGE
;
371 // add edit support contact info to message
372 finalMessage
+= MessagingUtils
.CONTACT_MESSAGE
;
375 MultiStatus ms
= new MultiStatus(pluginId
,
377 childStatuses
.toArray(new Status
[] {}),
378 throwable
.toString(),
381 errorDialog(title
, source
, throwable
, contextInfo
, finalMessage
, ms
, showReason
);
385 * Displays a dialog for an exception occurring in an operation.
387 * This will be either a {@link eu.etaxonomy.taxeditor.model.CdmErrorDialog} in case of a
388 * security runtime exception or a warning {@link org.eclipse.jface.dialogs.MessageDialog} in
389 * case of any other exception.
392 * a {@link java.lang.String} object.
394 * a {@link java.lang.Object} object.
396 * a {@link org.eclipse.core.runtime.IStatus} object.
398 public static void operationDialog(final Object source
,
400 final String pluginId
,
401 final String operationlabel
,
404 Display
.getDefault().asyncExec(new Runnable() {
408 MultiStatus info
= null;
411 // FIXME cannot access TaxonomicEditorPlugin.PLUGIN_ID from here
412 // String PID = TaxonomicEditorPlugin.PLUGIN_ID;
413 String PID
= "eu.etaxonomy.taxeditor.application";
415 // checking security exceptions for every operation
416 RuntimeException securityRuntimeException
= SecurityExceptionUtils
.findSecurityRuntimeException(ex
);
418 // in case of a security exception it is a warning, else it is an error
419 if(securityRuntimeException
!= null){
420 title
= "Your changes could not be saved!";
421 warningDialog(title
, source
, String
.format("You are missing sufficient permissions for the operation \"%s\". %s", operationlabel
, hint
));
423 title
= "Error executing operation";
424 errorDialog(title
, source
, String
.format("An error occured while executing %s. %s", operationlabel
, hint
), pluginId
, ex
, true);
437 * Displays a question {@link org.eclipse.jface.dialogs.MessageDialog}.
440 * a {@link java.lang.String} object.
442 * a {@link java.lang.String} object.
445 public static boolean confirmDialog(String title
, String message
) {
446 return MessageDialog
.openQuestion(AbstractUtility
.getShell(), title
, message
);
450 * Displays a message {@link org.eclipse.jface.dialogs.MessageDialog}.
456 public static void messageDialog(final String title
, final Object source
, final String message
) {
457 MessagingUtils
.messageDialog(title
, source
, message
, null, true);
463 * Displays an error {@link org.eclipse.jface.dialogs.MessageDialog}.
468 * The object where the warning was generated (used by log4j)
470 * An informative String to be presented to the user
474 * a Throwable if one exists or null
476 public static void messageDialog(final String title
,
478 final String message
,
480 MessagingUtils
.messageDialog(title
, source
, message
, t
, true);
484 * Displays an error {@link org.eclipse.jface.dialogs.MessageDialog}.
489 * The object where the warning was generated (used by log4j)
491 * An informative String to be presented to the user
495 * a Throwable if one exists or null
497 public static void messageDialog(final String title
,
499 final String message
,
503 Display
.getDefault().asyncExec(new Runnable() {
507 MessageDialog
.openError(AbstractUtility
.getShell(), title
, message
+ getCauseRecursively(t
));
508 Class
<?
extends Object
> clazz
= source
!= null ? source
509 .getClass() : this.getClass();
510 error(clazz
, message
, t
);
516 MessageDialog
.openError(AbstractUtility
.getShell(), title
, message
+ getCauseRecursively(t
));
517 Class
<?
extends Object
> clazz
= source
!= null ? source
.getClass() : TaxeditorStorePlugin
.class;
518 error(clazz
, message
, t
);
522 public static String
getCauseRecursively(Throwable t
) {
527 if(t
.getCause() != null){
528 return getCauseRecursively(t
.getCause());
530 return String
.format("\n\nException: %s\nMessage: %s", t
.getClass().getSimpleName(), t
.getMessage());
535 * Displays a warning {@link org.eclipse.jface.dialogs.MessageDialog}.
541 public static void warningDialog(String title
, Object source
,
543 MessagingUtils
.warningDialog(title
, source
, status
.getMessage());
547 * Standard warning dialog for the case when the application is not yet connected to the datasource
551 public static void noDataSourceWarningDialog(Object source
) {
554 "Application is not connected to a datastore",
556 "The requested operation is only available when "
557 + "connected to a datasource. You may choose a datasource to connect to or create a new one in the datasource view.");
561 * Standard warning dialog for the case when the datasource is not available
565 public static void dataSourceNotAvailableWarningDialog(Object source
) {
568 "The datasource is not available",
570 "The editor is not connected to a datasource. Maybe the datasource is not available.");
575 * Displays a warning {@link org.eclipse.jface.dialogs.MessageDialog}.
580 * The object where the warning was generated (used by log4j)
582 * An informative String to be presented to the user
584 public static void warningDialog(final String title
, final Object source
, final String message
) {
585 Display
.getDefault().asyncExec(new Runnable() {
589 MessageDialog
.openWarning(AbstractUtility
.getShell(), title
, message
);
590 Class
<?
extends Object
> clazz
= source
!= null ? source
591 .getClass() : AbstractUtility
.class;
592 warn(clazz
, message
);
598 * Displays an information {@link org.eclipse.jface.dialogs.MessageDialog}.
603 public static void informationDialog(final String title
, final IStatus status
) {
604 MessagingUtils
.informationDialog(title
, status
.getMessage());
608 * Displays an information {@link org.eclipse.jface.dialogs.MessageDialog}.
611 * a {@link java.lang.String} object.
613 * a {@link java.lang.String} object.
615 public static void informationDialog(final String title
,
616 final String message
) {
617 Display
.getDefault().asyncExec(new Runnable() {
621 MessageDialog
.openInformation(AbstractUtility
.getShell(), title
, message
);
627 * Open a message box that informs the user about unimplemented
628 * functionality. This method is for developer convenience.
631 * a {@link java.lang.Object} object.
633 public static void notImplementedMessage(Object source
) {
634 warningDialog("Not yet implemented", source
,
635 "This functionality is not yet implemented.");