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
.test
.integration
.SecurityExceptionUtils
;
18 import eu
.etaxonomy
.taxeditor
.store
.CdmStore
;
19 import eu
.etaxonomy
.taxeditor
.store
.internal
.TaxeditorStorePlugin
;
22 * Utility class which handles all the messaging information generated by the
25 * This includes logging as well as dialogs.
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 public static final String WIDGET_IS_DISPOSED_MESSAGE
= "A widget was called, which was already disposed";
39 * Gets the Log4J logger for a given class
42 * a {@link java.lang.Class} object.
43 * @return a {@link org.apache.log4j.Logger} object.
45 public static Logger
getLog4JLogger(Class clazz
) {
46 return Logger
.getLogger(clazz
);
50 * Logs details from a given Status object
53 * a {@link org.eclipse.core.runtime.IStatus} object.
55 private static void log(IStatus status
) {
56 TaxeditorStorePlugin
.getDefault().getLog().log(status
);
60 * Logs a status object as information.
63 * a {@link org.eclipse.core.runtime.IStatus} object.
65 public static void info(IStatus status
) {
70 * Logs a string as information.
73 * a {@link java.lang.String} object.
75 public static void info(String message
) {
76 IStatus status
= new Status(IStatus
.INFO
, AbstractUtility
.getPluginId(), message
);
81 * Logs an exception from a given source as a warning.
86 public static void warn(Class source
, Throwable t
) {
87 IStatus status
= new Status(IStatus
.WARNING
, AbstractUtility
.getPluginId(), t
.getMessage(), t
);
88 MessagingUtils
.getLog4JLogger(source
).warn(t
);
93 * Logs a status object from a given source as a warning.
98 public static void warn(Class source
, IStatus status
) {
99 MessagingUtils
.getLog4JLogger(source
).warn(status
.getMessage(), status
.getException());
104 * Logs a string from a given source as a warning.
108 * a {@link java.lang.Class} object.
110 * a {@link java.lang.String} object.
112 public static void warn(Class source
, String message
) {
113 IStatus status
= new Status(IStatus
.WARNING
, AbstractUtility
.getPluginId(), message
);
114 MessagingUtils
.getLog4JLogger(source
).warn(message
);
119 * Logs a status object from a given source as an error.
123 * a {@link java.lang.Class} object.
125 * a {@link org.eclipse.core.runtime.IStatus} object.
127 public static void error(Class source
, IStatus status
) {
128 getLog4JLogger(source
)
129 .error(status
.getMessage(), status
.getException());
134 * Logs a string and exception from a given source as an error.
138 * a {@link java.lang.Class} object.
140 * a {@link java.lang.String} object.
142 * a {@link java.lang.Throwable} object.
144 public static void error(Class source
, String message
, Throwable t
) {
145 IStatus status
= new Status(IStatus
.ERROR
, AbstractUtility
.getPluginId(), message
, t
);
146 error(source
, status
);
152 * Logs an exception from a given source as an error.
156 * a {@link java.lang.Class} object.
158 * a {@link java.lang.Throwable} object.
160 public static void error(Class source
, Throwable t
) {
161 error(source
.getClass(), t
.getMessage(), t
);
167 * Returns a list of strings, providing info on,
170 * - server (address + source name)
171 * - db schema version
175 public static List
<String
> getContextInfo() {
176 List
<String
> contextInfo
= new ArrayList
<String
>();
178 String schemaVersion
= "";
183 version
= Platform
.getBundle("eu.etaxonomy.taxeditor.application").getHeaders().get(org
.osgi
.framework
.Constants
.BUNDLE_VERSION
);
185 if(CdmStore
.getActiveCdmSource() != null ) {
186 login
= CdmStore
.getLoginManager().getAuthenticatedUser().getUsername();
187 name
= CdmStore
.getActiveCdmSource().getName();
188 schemaVersion
= CdmStore
.getActiveCdmSource().getDbSchemaVersion();
189 server
= CdmStore
.getActiveCdmSource().getServer();
192 } catch (Exception e
) {
195 contextInfo
.add("login : " + login
);
196 contextInfo
.add("editor version : " + version
);
197 contextInfo
.add("server : " + server
+ " / " + name
);
198 contextInfo
.add("schema version : " + schemaVersion
);
199 contextInfo
.add("os : " + System
.getProperty("os.name")+" "+System
.getProperty("os.version")+" "+System
.getProperty("os.arch"));
200 contextInfo
.add("java : "+System
.getProperty("java.version"));
205 public static String
getStackTraceAndContextInfo(Throwable t
, List
<String
> contextInfo
) {
206 StringBuffer stackTraceAndContextInfo
= new StringBuffer();
207 Throwable throwable
= t
;
209 for(String infoItem
: contextInfo
) {
210 stackTraceAndContextInfo
.append(infoItem
+ System
.getProperty("line.separator"));
213 StringWriter sw
= new StringWriter();
215 if(throwable
== null) {
216 throwable
= getDefaultThrowable();
218 throwable
.printStackTrace(new PrintWriter(sw
));
220 stackTraceAndContextInfo
.append(sw
.toString());
222 return stackTraceAndContextInfo
.toString();
225 public static String
getContextInfo(List
<String
> contextInfo
) {
226 StringBuffer scontextInfoStringBuffer
= new StringBuffer();
229 for(String infoItem
: contextInfo
) {
230 scontextInfoStringBuffer
.append(infoItem
+ System
.getProperty("line.separator"));
235 return scontextInfoStringBuffer
.toString();
238 private static Throwable
getDefaultThrowable() {
239 return new Throwable("Error thrown but no associated exception");
245 * Displays a {@link eu.etaxonomy.taxeditor.model.CdmErrorDialog}.
254 private static void errorDialog(final String title
,
257 final List
<String
> contextInfo
,
258 final String message
,
259 final MultiStatus status
,
260 final boolean showReason
) {
262 Display
.getDefault().asyncExec(new Runnable() {
266 String stackTraceWithContext
= getStackTraceAndContextInfo(t
, contextInfo
);
267 CdmErrorDialog ced
= new CdmErrorDialog(AbstractUtility
.getShell(), title
, message
, status
, stackTraceWithContext
, showReason
);
269 Class
<?
extends Object
> clazz
= source
!= null ? source
.getClass() : this.getClass();
272 IStatus singleStatus
= new Status(IStatus
.ERROR
,
275 new Exception(stackTraceWithContext
));
277 error(clazz
, singleStatus
);
282 public static void errorDialog(final String title
,
284 final String message
,
285 final String pluginId
,
287 boolean addContactMesg
) {
288 errorDialog(title
, source
, message
, pluginId
, t
, addContactMesg
, true);
292 * Displays a {@link eu.etaxonomy.taxeditor.model.CdmErrorDialog}.
300 public static void errorDialog(final String title
,
302 final String message
,
303 final String pluginId
,
305 boolean addContactMesg
,
306 boolean showReason
) {
308 Throwable throwable
= t
;
309 StringBuffer sbStackTrace
= new StringBuffer();
311 // We need to build a MultiStatus object since the simple
312 // idea of writing out the stack trace as a single string
313 // leads to a single line on windows
314 List
<Status
> childStatuses
= new ArrayList
<Status
>();
317 List
<String
> contextInfo
= getContextInfo();
318 for(String infoItem
: contextInfo
) {
319 childStatuses
.add(new Status(IStatus
.ERROR
, pluginId
, infoItem
));
322 if(throwable
== null) {
323 throwable
= getDefaultThrowable();
329 for(Throwable th
: ExceptionUtils
.getThrowables(throwable
)) {
330 // add main exception
332 for (StackTraceElement ste
: th
.getStackTrace()) {
333 childStatuses
.add(new Status(IStatus
.ERROR
, pluginId
, " at " + ste
.toString()));
336 // add recursive causes
338 childStatuses
.add(new Status(IStatus
.ERROR
, pluginId
, ""));
339 String msg
= th
.toString();
340 childStatuses
.add(new Status(IStatus
.ERROR
, pluginId
, "Caused by : " + msg
));
342 for (StackTraceElement ste
: th
.getStackTrace()) {
343 // add only pre-defined number of trace elements
344 if(traceCount
> maxTraces
) {
345 childStatuses
.add(new Status(IStatus
.ERROR
, pluginId
, " ...."));
348 // build & add status
349 childStatuses
.add(new Status(IStatus
.ERROR
, pluginId
, " at " + ste
.toString()));
356 String finalMessage
= message
;
358 if(finalMessage
== null || finalMessage
.isEmpty()) {
359 finalMessage
= DEFAULT_MESSAGE
;
363 // add edit support contact info to message
364 finalMessage
+= MessagingUtils
.CONTACT_MESSAGE
;
367 MultiStatus ms
= new MultiStatus(pluginId
,
369 childStatuses
.toArray(new Status
[] {}),
370 throwable
.toString(),
373 errorDialog(title
, source
, throwable
, contextInfo
, finalMessage
, ms
, showReason
);
377 * Displays a dialog for an exception occurring in an operation.
379 * This will be either a {@link eu.etaxonomy.taxeditor.model.CdmErrorDialog} in case of a
380 * security runtime exception or a warning {@link org.eclipse.jface.dialogs.MessageDialog} in
381 * case of any other exception.
384 * a {@link java.lang.String} object.
386 * a {@link java.lang.Object} object.
388 * a {@link org.eclipse.core.runtime.IStatus} object.
390 public static void operationDialog(final Object source
,
392 final String pluginId
,
393 final String operationlabel
,
396 Display
.getDefault().asyncExec(new Runnable() {
400 MultiStatus info
= null;
403 // FIXME cannot access TaxonomicEditorPlugin.PLUGIN_ID from here
404 // String PID = TaxonomicEditorPlugin.PLUGIN_ID;
405 String PID
= "eu.etaxonomy.taxeditor.application";
407 // checking security exceptions for every operation
408 RuntimeException securityRuntimeException
= SecurityExceptionUtils
.findSecurityRuntimeException(ex
);
410 // in case of a security exception it is a warning, else it is an error
411 if(securityRuntimeException
!= null){
412 title
= "Your changes could not be saved!";
413 warningDialog(title
, source
, String
.format("You are missing sufficient permissions for the operation \"%s\". %s", operationlabel
, hint
));
415 title
= "Error executing operation";
416 errorDialog(title
, source
, String
.format("An error occured while executing %s. %s", operationlabel
, hint
), pluginId
, ex
, true);
429 * Displays a question {@link org.eclipse.jface.dialogs.MessageDialog}.
432 * a {@link java.lang.String} object.
434 * a {@link java.lang.String} object.
437 public static boolean confirmDialog(String title
, String message
) {
438 return MessageDialog
.openQuestion(AbstractUtility
.getShell(), title
, message
);
442 * Displays a message {@link org.eclipse.jface.dialogs.MessageDialog}.
448 public static void messageDialog(final String title
, final Object source
, final String message
) {
449 MessagingUtils
.messageDialog(title
, source
, message
, null, true);
455 * Displays an error {@link org.eclipse.jface.dialogs.MessageDialog}.
460 * The object where the warning was generated (used by log4j)
462 * An informative String to be presented to the user
466 * a Throwable if one exists or null
468 public static void messageDialog(final String title
,
470 final String message
,
472 MessagingUtils
.messageDialog(title
, source
, message
, t
, true);
476 * Displays an error {@link org.eclipse.jface.dialogs.MessageDialog}.
481 * The object where the warning was generated (used by log4j)
483 * An informative String to be presented to the user
487 * a Throwable if one exists or null
489 public static void messageDialog(final String title
,
491 final String message
,
495 Display
.getDefault().asyncExec(new Runnable() {
499 MessageDialog
.openError(AbstractUtility
.getShell(), title
, message
+ getCauseRecursively(t
));
500 Class
<?
extends Object
> clazz
= source
!= null ? source
501 .getClass() : this.getClass();
502 error(clazz
, message
, t
);
508 MessageDialog
.openError(AbstractUtility
.getShell(), title
, message
+ getCauseRecursively(t
));
509 Class
<?
extends Object
> clazz
= source
!= null ? source
.getClass() : TaxeditorStorePlugin
.class;
510 error(clazz
, message
, t
);
514 public static String
getCauseRecursively(Throwable t
) {
519 if(t
.getCause() != null){
520 return getCauseRecursively(t
.getCause());
522 return String
.format("\n\nException: %s\nMessage: %s", t
.getClass().getSimpleName(), t
.getMessage());
527 * Displays a warning {@link org.eclipse.jface.dialogs.MessageDialog}.
533 public static void warningDialog(String title
, Object source
,
535 MessagingUtils
.warningDialog(title
, source
, status
.getMessage());
539 * Standard warning dialog for the case when the application is not yet connected to the datasource
543 public static void noDataSourceWarningDialog(Object source
) {
546 "Application is not connected to a datastore",
548 "The requested operation is only available when "
549 + "connected to a datasource. You may choose a datasource to connect to or create a new one in the datasource view.");
553 * Displays a warning {@link org.eclipse.jface.dialogs.MessageDialog}.
558 * The object where the warning was generated (used by log4j)
560 * An informative String to be presented to the user
562 public static void warningDialog(final String title
, final Object source
, final String message
) {
563 Display
.getDefault().asyncExec(new Runnable() {
567 MessageDialog
.openWarning(AbstractUtility
.getShell(), title
, message
);
568 Class
<?
extends Object
> clazz
= source
!= null ? source
569 .getClass() : AbstractUtility
.class;
570 warn(clazz
, message
);
576 * Displays an information {@link org.eclipse.jface.dialogs.MessageDialog}.
581 public static void informationDialog(final String title
, final IStatus status
) {
582 MessagingUtils
.informationDialog(title
, status
.getMessage());
586 * Displays an information {@link org.eclipse.jface.dialogs.MessageDialog}.
589 * a {@link java.lang.String} object.
591 * a {@link java.lang.String} object.
593 public static void informationDialog(final String title
,
594 final String message
) {
595 Display
.getDefault().asyncExec(new Runnable() {
599 MessageDialog
.openInformation(AbstractUtility
.getShell(), title
, message
);
605 * Open a message box that informs the user about unimplemented
606 * functionality. This method is for developer convenience.
609 * a {@link java.lang.Object} object.
611 public static void notImplementedMessage(Object source
) {
612 warningDialog("Not yet implemented", source
,
613 "This functionality is not yet implemented.");