Error catalogue

There is interface org.openhubframework.openhub.api.exception.ErrorExtEnum for defining own error catalogue that is displayed in admin GUI.

It allows consuments of your services to see possible error codes and be able to handle them.

/**
 * Catalog of internal error codes.
 *
 * @author Petr Juza
 */
@ErrorCodeCatalog("OHF")
public enum InternalErrorEnum implements ErrorExtEnum {

    /**
     * unspecified error
     */
    E100("unspecified error"),

    /**
     * the request message is not valid against to XSD schema
     */
    E101("the request message is not valid against to XSD schema"),

    /**
     * the validation error
     */
    E102("the validation error"),

    /**
     * I/O error during communication with target system
     */
    E103("I/O error during communication with target system"),

Exceptions hierarchy

All OpenHub framework exceptions are in package org.openhubframework.openhub.api.exception:

How it works?

Basic error handling concept is well-documented in Apache Camel.

Basic algorithm of error handling is implemented in parent class of routes - org.openhubframework.openhub.api.route.AbstractBasicRoute.

Is message asynchronous?

If yes then next processing steps are determined according to exception/error type:


Example of error handling in communication via Web Services with external system:

private static final Class[] FATAL_EXCEPTIONS = new Class[] {AlreadyExistsException.class,
	ValidityMismatchException.class, ChargingKeyNotFoundException.class, NonExistingProductOfferingException.class, IllegalOperationException.class};
private static final Class[] NEXT_HANDLING_EXCEPTIONS = new Class[] {CustomerNotFoundException.class,
	CustomerAccountNotFoundException.class};
 
 
.doTry()
    .to(getBillingUri())
    // explicitly converts to UTF-8
    .convertBodyTo(String.class, "UTF-8")
    // XML -> specific payload implementation of child for error check
    .unmarshal(getUnmarshalDataFormat())
.doCatch(WebServiceIOException.class)
    .setProperty(ExceptionTranslator.EXCEPTION_ERROR_CODE, constant(ErrorEnum.E600))
    .to(AsynchConstants.URI_ERROR_HANDLING)
    // we handle all exceptions in the same way there are two big catches here
.doCatch(NEXT_HANDLING_EXCEPTIONS)
    .setProperty(ExceptionTranslator.EXCEPTION_ERROR_CODE, constant(ErrorEnum.E602))
    .to(AsynchConstants.URI_ERROR_HANDLING)
.doCatch(FATAL_EXCEPTIONS)
    .setProperty(ExceptionTranslator.EXCEPTION_ERROR_CODE, constant(ErrorEnum.E601))
    .to(AsynchConstants.URI_ERROR_FATAL)
.end();


If not (=message is synchronous) then error handling is redirected to URL: AsynchConstants.URI_EX_TRANSLATION and then to ExceptionTranslator. Exception is propagated back to source system.

.onException(WebServiceIOException.class)
	.handled(true)
    .setProperty(ExceptionTranslator.EXCEPTION_ERROR_CODE, constant(ErrorEnum.E600))
    .process(ExceptionTranslator.getInstance())
	.end()
.onException(FATAL_EXCEPTIONS)
    .handled(true)
    .setProperty(ExceptionTranslator.EXCEPTION_ERROR_CODE, constant(ErrorEnum.E601))
    .process(ExceptionTranslator.getInstance())
    .end()
.onException(NEXT_HANDLING_EXCEPTIONS)
    .handled(true)
    .setProperty(ExceptionTranslator.EXCEPTION_ERROR_CODE, constant(ErrorEnum.E602))
    .process(ExceptionTranslator.getInstance())
    .end()

.to(getSapUri())
// explicitly converts to UTF-8
.convertBodyTo(String.class, "UTF-8")
// XML -> specific payload implementation of child for error check
.unmarshal(getUnmarshalDataFormat())

Custom error processing

Error handling concept in described in Apache Camel where you can find more details.

In common there are two types of error handling - routes specific and global, there are two ways how to catch exceptions - with Exception Clause or with DoTry Clause.

Mapping exceptions in WSDL

WSDL contract allows to define exceptions (aka faults) directly in operation definition.

 <wsdl:operation name="createSubscriber">
            <wsdl:input message="tns:createSubscriber" name="createSubscriber">
            </wsdl:input>
            <wsdl:output message="tns:createSubscriberResponse" name="createSubscriberResponse">
            </wsdl:output>
            <wsdl:fault message="tns:CustomerAccountNotFoundException" name="CustomerAccountNotFoundException">
            </wsdl:fault>
            <wsdl:fault message="tns:CustomerNotFoundException" name="CustomerNotFoundException">
            </wsdl:fault>
            <wsdl:fault message="tns:AlreadyExistsException" name="AlreadyExistsException">
            </wsdl:fault>
        </wsdl:operation>

 

Example of fault response with exception detail:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
         <soap:Body>
             <soap:Fault>
                 <faultcode>soap:Server</faultcode>
                 <faultstring>Bussiness violation</faultstring>
                 <detail>
                     <ns2:ValidityMismatch xmlns:ns2="http://ws.lbss.com/">
                         <message>
                        Product offering with externalNo:-1 is not valid on date:Sat May 25 00:00:00 CEST 2013
                         </message>
                     </ns2:ValidityMismatch>
                 </detail>
             </soap:Fault>
         </soap:Body>
</soap:Envelope>


There is helper parent class AbstractSoapExceptionFilter for mapping SOAP fault exceptions (SoapFaultClientException) to internal Java exceptions from WSDL contract.

Example of CrmSoapExceptionFilter:

.onException(WebServiceIOException.class)
	.handled(true)
    .setProperty(AsynchConstants.EXCEPTION_ERROR_CODE, constant(ErrorEnum.E403))
    .process(ExceptionTranslator.getInstance())
    .end()
.onException(SoapFaultClientException.class)
    .handled(true)
    .process(new CrmSoapExceptionFilter(false))
    .end()