BioUML exceptions
This page or section is under construction right now. |
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 byOptionEx.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
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.