BioUML exceptions

From BioUML platform
Revision as of 12:24, 11 September 2013 by Tagir Valeev (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

This article describes new BioUML exception handling concept introduced in version 0.9.6.

Contents

Overview

BioUML exceptions (short: BUEX) are descendants of class BiosoftException. All other exceptions are called raw exceptions. Now it's undesired to throw raw exception in BioUML code except some cases when particular part of code can become BioUML-independent.

Class BiosoftException extends RuntimeException, thus it's not necessary (but desired!) to declare it in throws clause.

Exception descriptors

Each exception type is defined by exception descriptors which are instances of ExceptionDescriptor class. Exception descriptor contains the following properties:

Level
Exception level (described below)
Code
Text string which together with level refers to particular error situation. For example, code 'NPE' of level 'System' refers to null pointer exception. Usually level and code are written together as 'System.NPE'
Logging level
How this exception should be displayed in log:
  • None - Do not log this Exception even if requested
  • Summary - Log summary+properties which are not directly specified in summary message
  • TraceIfNoCause - Log summary+properties+trace if exception has no cause
  • Trace - Log summary+properties+trace
Template
User-friendly message template. Templates can use all custom properties defined by exception referring to them like $path$. Bean properties of these properties can also be used like $cause/class/simpleName$ (the same syntax is used by OptionEx.makeAutoProperty).

User code should not use exception descriptors. Instead separate classes for individual exceptions should be created which initialize BiosoftException with specific descriptor defined as constant in the same class. For example, QuotaException defines ED_QUOTA descriptor.

Exception levels

Exceptions are divided to several categories called exception levels. Low-level BioUML exceptions include:

System
Low level errors: out of memory, NPE, programmatic errors, etc.
SQL
Low level SQL database access problem
IO
Low level input/output access problem
Network
Low level network problem

High-level BioUML exceptions include:

Repository
Repository problem (unable to get, put, delete element, etc.)
Security
Access violation, quota, etc.
Computational
Computational problem during some data analysis
Parameter
User input problem

List of levels may change in future.

Exception properties

Each BioUML exception has the following properties:

ID
Autoincrementing number starting from 1 identifying the exception.
Descriptor
Exception descriptor associated with this exception

Also BioUML exception has custom properties defined in DynamicPropertySet. They can be logged and used in generating user-friendly messages.

Chaining

BioUML exceptions can be chained. Usually (but not always) high-level exception has low-level exception cause, which may have raw exception as the cause. Every raw exception can be converted to BioUML exception using ExceptionRegistry.translateException(Throwable) method (if BioUML exception was passed to this method it will just return it). However in many cases it's desired to create BioUML exception manually as you may specify additional details. BioUML exception should not be the cause of raw exception. Low-level exception should has raw exception or nothing as the cause (not another BioUML exception).

Reporting

Error log in BioUML workbench.

There are two ways to report the BioUML exception: to display it to user and to log it. All BioUML exceptions are logged into special logger error.log. In BioUML workbench it's displayed as a separate sub tab of Application log viewpart. On BioUML server this might be appended to separate file depending on your server.lcf configuration. Ideally all low-level technical information including all the stacktraces must go there. Messages displayed to the user (including ones displayed in normal Application log) should be more user-friendly.

For example, this is how the exception is reported in Application log:

ERROR :  Cannot create collection data/Collaboration/Lan_test/Data/MACS/profile
Reason: Internal error occured (Java class ru.biosoft.bsa.analysis.chipseqprofile.PeakProfileTransformer not found). Please check error log for BUEX#136.

And this is how the same exception is reported in Error log:

ERROR :  BUEX#137/Repository.CannotCreate: Cannot create collection data/Collaboration/Lan_test/Data/MACS/profile
Caused by: BUEX#136/System.NoClass: Internal error occured (Java class ru.biosoft.bsa.analysis.chipseqprofile.PeakProfileTransformer not found).
Caused by: java.lang.ClassNotFoundException: Can't load class ru.biosoft.bsa.analysis.chipseqprofile.PeakProfileTransformer
       at ru.biosoft.access.CollectionFactory.loadClass(CollectionFactory.java:269)
       at ru.biosoft.access.TransformedDataCollection.<init>(TransformedDataCollection.java:45)
       at sun.reflect.GeneratedConstructorAccessor12.newInstance(Unknown Source)
       at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
       at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
       at ru.biosoft.access.CollectionFactory.createCollection(CollectionFactory.java:195)
       at ru.biosoft.access.CollectionFactory.createCollection(CollectionFactory.java:148)
       at ru.biosoft.access.LocalRepository.createCollection(LocalRepository.java:224)
       at ru.biosoft.access.LocalRepository.init(LocalRepository.java:131)
(many more stacktrace lines)

To log the exception, use BiosoftException.log() method. Each exception can be logged only once in order not to pollute the error log with dublicates.

To get the user-friendly message use BiosoftException.getMessage() method. This method provides one-line description of the problem followed by the description of the cause. If cause is absent or it's raw exception, it's not returned. By default for low-level exceptions additional message added like Please check error log for BUEX#... for BioUML workbench or Please contact application vendor supplying ID BUEX#... for BioUML server.

Usage guidelines

Try not to 'swallow' the exception if you cannot handle it properly. Printing the exception to log and returning null is bad practice as calling code won't know what's going on. Also printing to the log might be useless for BioUML web edition as messages from your log object may not be passed to the client at all. Consider wrapping the exception to higher-level BioUML exception and throw it outside. If you think that user might be interested in exception, but you can continue ignoring it, use ExceptionRegistry.log(Throwable), which will translate an exception to BioUML exception, log it and return the user-friendly message.

Try not to create many exception descriptors and classes. When you need an exception try to reuse existing ones. If nothing suits your situation, try to create more-less universal new descriptor which can be used in other situations as well.

Currently the prefered way to get the data element is DataElementPath.getDataElement(Class<T>). The parameter is the wanted element class. This method never returns null. Instead it throws BioUMLRepositoryException if element cannot be fetched or has invalid class.

Personal tools
Namespaces

Variants
Actions
BioUML platform
Community
Modelling
Analysis & Workflows
Collaborative research
Development
Virtual biology
Wiki
Toolbox