Exception Handling Process Overview:

While implementing any service that will be deployed and run on JLupin Next Server, the final programmer may or may not declare the method`s exceptions.

First, let’s take a look at the service of a regular exception thrown by any service:

package com.jlupin.sampleapp.service;

public class SampleExceptionService {

   public void foo() throws Throwable {
          throw new Exception("an foo error occurred");
   }
}

The idea here is that the foo method has "throws Throwable" in its declaration which allows any kind of exception to be thrown. Below effects of generation of the above mentioned service and foo method are presented:

[2016-07-18 11:48:04] CLASS:com.jlupin.impl.client.command.JLupinDefaultCommandImpl MESSAGE ID:16 SESSION ID:sessId:004 REQUEST ID:reqId:00123 LEVEL:DEBUG THREAD:1 METHOD:execute LINE:152 LOG:STOP command process - process time (milliseconds):299 with request id:reqId:00123 and session id:sessId:004 and output object:JLupinOutputParameter{jLupinExceptionModel=JLupinExceptionModel{errorMessage='unexpected error occurred while trying to call service sampleExceptionService and method foo, error details: an foo error occurred', errorCode='com.jlupin.impl.handler.service.JLupinDefaultServiceExceptionHandlerImpl.error.002', errorReasons=null, errorSolutions=null, sourceStackTrace='java.lang.Exception: an foo error occurred
    at com.jlupin.sampleapp.service.SampleExceptionService.foo(SampleExceptionService.java:7)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.jlupin.impl.util.JLupinUtil.invokeMethod(JLupinUtil.java:721)
    at com.jlupin.impl.processor.JLupinDefaultServiceProcessorImpl.invoke(JLupinDefaultServiceProcessorImpl.java:304)
    at com.jlupin.impl.entrypoint.defaults.strategy.invoke.impl.base.JLupinInvokeServiceStrategyBaseImpl.executeService(JLupinInvokeServiceStrategyBaseImpl.java:28)
    at com.jlupin.impl.entrypoint.defaults.strategy.invoke.impl.JLupinInvokeServiceStrategyInCurrentThreadImpl.invokeService(JLupinInvokeServiceStrategyInCurrentThreadImpl.java:36)
    at com.jlupin.impl.entrypoint.defaults.JLupinDefaultEntryPointImpl.doEntry(JLupinDefaultEntryPointImpl.java:35)
    at com.jlupin.impl.server.mainloop.strategy.base.JLupinBaseAbstractServiceStrategy$ThreadCallable.call(JLupinBaseAbstractServiceStrategy.java:102)
    at com.jlupin.impl.server.mainloop.strategy.base.JLupinBaseAbstractServiceStrategy$ThreadCallable.call(JLupinBaseAbstractServiceStrategy.java:84)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
', additionalErrorCodeMap=null}, jLupinServiceDTO=null, executedServiceError=true, resultObject=null}

Default error message generated by JLupinDefaultServiceExceptionHandlerImpl:

unexpected error occurred while trying to call service sampleExceptionService and method foo, error details: an foo error occurred

Default error message includes the most important information: service name, method name and message taken directly from the thrown exception. It also includes error code – in this case: com.jlupin.impl.handler.service.JLupinDefaultServiceExceptionHandlerImpl.error.002 and stackstrace. Object including error details in Data Transfer Object (DTO) JLupinOutputParameter is JLupinExceptionModel – we can take information from output that is interesting for us. Fields of JLupinExceptionModel class were shown at the end of the section. All exceptions handled are executed by the class which implements the JLupinServiceExceptionHandler interface. Examine the default exception handler action - JLupinDefaultServiceExceptionHandlerImpl.

As an example, we'll use the following service - SampleExceptionService_01.

package com.jlupin.sampleapp.service;

import com.jlupin.interfaces.common.exception.base.JLupinBaseErrorCodeException;

public class SampleExceptionService_01 {

    @Override
    public void foo() throws Throwable {

       throw new JLupinBaseErrorCodeException(
                "com.jlupin.sampleapp.service.error.001",
                "user can not be authenticated because login or password is incorrect");

    }
}

The idea here is that the foo method has 'throws Throwable' in its declaration which allows any kind of exception to be thrown. Therefore, in the first step JLupinDefaultServiceExceptionHandlerImpl implementation examines whether or not the JLupinBaseErrorCodeException object was thrown. If so, JLupinDefaultServiceExceptionHandlerImpl implementation redirects the execution to the JLupinDefaultErrorMessageProducerImpl implementation which seeks the value of key which has been thrown by the service, in this case 'com.jlupin.sampleapp.service.error.001'. The keys in default congiguration are located in messages.properties (for proper microservice) and global_messages.properties (for JLupinNextServer default messages) files. If the key and value is found by JLupinDefaultServiceExceptionHandlerImpl, it shows a message from the aforementioned files. If not, the following message appears: "user can not be authenticated because login or password is incorrect" (as default message for JLupinDefaultServiceExceptionHandlerImpl).

The effect is shown in the following listing:

[2014-05-19 08:25:10] CLASS:com.jlupin.impl.client.command.JLupinDefaultCommandImpl MESSAGE ID:16  
SESSION ID:d9bd9b5ee19071c2b108302ee43e121a0382876a49bac45ea517ae8e1681436e  
REQUEST ID:f9144cfdbff42c78acf0e424a9a6b3d399e2d2f5385890f854bf49d95b1d4076  
LEVEL:INFO THREAD:1 METHOD:execute LINE:122  
LOG:STOP command process - process time (milliseconds):172 with request  
id:f9144cfdbff42c78acf0e424a9a6b3d399e2d2f5385890f854bf49d95b1d4076 and  
session id:d9bd9b5ee19071c2b108302ee43e121a0382876a49bac45ea517ae8e1681436e  
and output object:JLupinOutputParameter{jLupinExceptionModel=JLupinExceptionModel
{errorMessage='user can not be authenticated because login or password is  
incorrect', errorCode='com.jlupin.sampleapp.service.error.001', errorReasons=[],  
errorSolutions=[], sourceStackTrace='com.jlupin.interfaces.common.exception.base.JLupinBaseErrorCodeException:  
user can not be authenticated because login or password is incorrect
    at com.jlupin.sampleapp.service.SampleExceptionService_01.foo(SampleExceptionService_01.java:14)
    at com.jlupin.impl.processor.JLupinDefaultServiceProcessorImpl.invoke(JLupinDefaultServiceProcessorImpl.java:144)
    at com.jlupin.impl.entrypoint.defaults.strategy.invoke.impl.base.JLupinInvokeServiceStrategyBaseImpl.executeService
(JLupinInvokeServiceStrategyBaseImpl.java:23)
    at com.jlupin.impl.entrypoint.defaults.strategy.invoke.impl.JLupinInvokeServiceStrategyInCurrentThreadImpl.invokeService
(JLupinInvokeServiceStrategyInCurrentThreadImpl.java:34)
    at com.jlupin.impl.entrypoint.defaults.JLupinDefaultEntryPointImpl.doEntry(JLupinDefaultEntryPointImpl.java:35)
    at com.jlupin.impl.server.JLupinDefaultBaseServerImpl$2.call(JLupinDefaultBaseServerImpl.java:205)
    at com.jlupin.impl.server.JLupinDefaultBaseServerImpl$2.call(JLupinDefaultBaseServerImpl.java:201)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)
', additionalErrorCodeMap={}}, jLupinServiceDTO=null, executedServiceError=true}

The next example shows how to catch an exception and how to format an error message using the parameters as an array of objects.

throw new JLupinBaseErrorCodeException( "com.jlupin.sampleapp.service.SampleExceptionService_02.error.001",
"user can not be authenticated, caused by:%s", new Object[] {th.getMessage()}, th);

The example also illustrates the use of adding a list of reasons why an error occurred (addErrorReason), a list of possible solutions (addErrorSolution) as well as additional error codes (addAdditionalErrorCode). JLupinDefaultServiceExceptionHandlerImpl is responsible for message formatting, and it uses JLupinDefaultErrorMessageProducerImpl.

package com.jlupin.sampleapp.service;

import com.jlupin.interfaces.common.exception.base.JLupinBaseErrorCodeException;

public class SampleExceptionService_02 {

    @Override
    public void foo() throws Throwable {
        try {
            //simulating exception from authorization subsystem
            throw new Exception("gateway time out (504)");
        }
        catch(Throwable th) {

            //create exception object but do not throw it yet
            JLupinBaseErrorCodeException jLupinBaseErrorCodeException = new JLupinBaseErrorCodeException(
                    "com.jlupin.sampleapp.service.SampleExceptionService_02.error.001",
                    "user can not be authenticated, caused by:%s",
                    new Object[] {th.getMessage()}, th);

            //add error possible reason
            jLupinBaseErrorCodeException.addErrorReason(
                "user authentication subsystem is not available at the moment",
                "com.jlupin.sampleapp.service.SampleExceptionService_02.error.002", null);

            //add error solution  
            jLupinBaseErrorCodeException.addErrorSolution(
                "contact with user authentication subsystem in mail: ua@dom.com",
                "com.jlupin.sampleapp.service.SampleExceptionService_02.error.003", null);

            //add additional error code
            jLupinBaseErrorCodeException.addAdditionalErrorCode("mobile_process", "error_not_show");
            throw  jLupinBaseErrorCodeException;
        }
    }

}

The effect is shown in the following listing:

JLupinOutputParameter{jLupinExceptionModel=JLupinExceptionModel{
errorMessage='user can not be authenticated, caused by:gateway time out (504)',  
errorCode='com.jlupin.sampleapp.service.SampleExceptionService_02.error.001',  
errorReasons=[user authentication subsystem is not available at the moment],  
errorSolutions=[contact with user authentication subsystem in mail: ua@dom.com],  
sourceStackTrace='com.jlupin.interfaces.common.exception.base.JLupinBaseErrorCodeException: user can not be authenticated, caused by:%s
    at com.jlupin.sampleapp.service.SampleExceptionService_02.foo(SampleExceptionService_02.java:17)
    at com.jlupin.impl.processor.JLupinDefaultServiceProcessorImpl.invoke(JLupinDefaultServiceProcessorImpl.java:144)
    at com.jlupin.impl.entrypoint.defaults.strategy.invoke.impl.base.JLupinInvokeServiceStrategyBaseImpl.executeService(
JLupinInvokeServiceStrategyBaseImpl.java:23)
    at com.jlupin.impl.entrypoint.defaults.strategy.invoke.impl.JLupinInvokeServiceStrategyInCurrentThreadImpl.invokeService(
JLupinInvokeServiceStrategyInCurrentThreadImpl.java:34)
    at com.jlupin.impl.entrypoint.defaults.JLupinDefaultEntryPointImpl.doEntry(JLupinDefaultEntryPointImpl.java:35)
    at com.jlupin.impl.server.JLupinDefaultBaseServerImpl$2.call(JLupinDefaultBaseServerImpl.java:205)
    at com.jlupin.impl.server.JLupinDefaultBaseServerImpl$2.call(JLupinDefaultBaseServerImpl.java:201)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)
Caused by: java.lang.Exception: gateway time out (504)
    at com.jlupin.sampleapp.service.SampleExceptionService_02.foo(SampleExceptionService_02.java:13)
    ... 11 more
', additionalErrorCodeMap={mobile_process=error_not_show}}, jLupinServiceDTO=null, executedServiceError=true}

Examine the JlupinDefaultServiceExceptionHandlerImpl implementation behaviour.
Assume that the service which has thrown an exception, has quite a substantial stack. The 'foo' method:

public class SampleExceptionService_03 {

    @Override
    public void foo() throws Throwable {
       fifth();
    }

    private void first() {
        throw new IllegalArgumentException("illegal first");
    }

    private void second() throws Throwable{

        try {
            first();
        } catch (Exception e) {
            throw new Exception("an error occurred during call first caused by:", e);
        }
    }

    private void third() throws Throwable{

        try {
            second();
        } catch (Exception e) {
            throw new Exception("an error occurred during call second caused by:", e);
        }
    }

    private void fourth() throws Throwable{

        try {
            third();
        } catch (Exception e) {
            throw new Exception("an error occurred during call third caused by:", e);
        }
    }

    private void fifth() throws Throwable{

        try {
            fourth();
        } catch (Exception e) {
            throw new Exception("an error occurred during call fourth caused by:", e);
        }
    }
}

exception handler is cofigured in default spring configuration file in SERVER_HOME/server-resources/spring-jlupin-default-configuration.xml:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">

    <bean id="jLupinAccessServices" class="com.jlupin.interfaces.service.access.enums.JLupinServiceAccessModeEnum"
          factory-method="valueOf">
        <constructor-arg>
            <value>PUBLIC</value>
        </constructor-arg>
    </bean>

    <bean id="jLupinMessageProducer"
          class="com.jlupin.impl.producer.service.errormessage.JLupinDefaultErrorMessageProducerImpl">
        <constructor-arg index="0" type="java.lang.String[]" value="messages, global_messages"/>
        <constructor-arg index="1"><ref bean="locale"/></constructor-arg>
        <constructor-arg index="2" type="java.lang.String" value="ISO-8859-1"/>
        <constructor-arg index="3" type="java.lang.String" value="UTF-8"/>
    </bean>

    <bean id="jLupinServiceExceptionHandler"
          class="com.jlupin.impl.handler.service.JLupinDefaultServiceExceptionHandlerImpl">
        <constructor-arg index="0"><ref bean="jLupinMessageProducer"/></constructor-arg>
    </bean>

    <bean id="locale" class="java.util.Locale">
        <constructor-arg index="0" type="java.lang.String" value="en"/>
    </bean>

</beans>

How does the JLupinDefaultServiceExceptionHandlerImpl implementation behave ?

The thrown exception is a subclass of the Exception that is why all the details of the thrown exception will be revealed. The server-resources directory is searched in order to find the global_messages.properties file and as a result the proper message is shown which is available under the com.jlupin.impl.handler.service.JLupinDefaultServiceExceptionHandlerImpl.error.002 key. The message might be displayed in any given language ( it is determined by the Locale object, which is passed by the client in the JLupinInputParameter object). When the aforementioned file is found, the proper service name and method name in which the exception occurred is given.

How will the details of the exception be formatted?

The JLupinDefaultServiceExceptionHandlerImpl implementation pulls the highest and the lowest message from the exception stack (this is the default configuration, which can be changed, it will be elaborated in a moment ). In out case the message from the fifth and first method :an error occurred during call fourth caused by: illegal first . After the service is called, the entire message will appear as the following:

unexpected error occurred while trying to call service sampleExceptionService_03 and method foo, error details:an error occurred during call fourth caused by:(highest cause):illegal first

The JLupinDefaultServiceExceptionHandlerImpl implementation may be configured so that the next exception message is taken although it is not desired behaviour. It is shown in the following example.

Here is the change of the exception handler configuration ( you need to set the buildHighestMessageFromStack variable to false in the given application configuration file):

<bean id="jLupinServiceExceptionHandler"
      class="com.jlupin.impl.handler.service.JLupinDefaultServiceExceptionHandlerImpl">
      <constructor-arg index="0"><ref bean="jLupinMessageProducer"/></constructor-arg>
      <property name="buildHighestMessageFromStack" value="false"/>
</bean>

now error message will be:

unexpected error occurred while trying to call service sampleExceptionService_03 and method foo, error details: an error occurred during call fourth caused by:

Another possible configuration is a stack of all messages from the entire exception stack. The following shows the change of the exception handler configuration (you need to set the buildMessageStack variable to true and the buildHighestMessageFromStack variable to false in the given application configuration file):

<bean id="jLupinServiceExceptionHandler"
        class="com.jlupin.impl.handler.service.JLupinDefaultServiceExceptionHandlerImpl">
        <constructor-arg index="0"><ref bean="jLupinMessageProducer"/></constructor-arg>
        <property name="buildMessageStack" value="true"/>
        <property name="buildHighestMessageFromStack" value="false"/>
</bean>

The result of the aforementioned configuration is shown below:

unexpected error occurred while trying to call service sampleExceptionService_03 and method foo, error details: an error occurred during call fourth caused by: an error occurred during call third caused by: an error occurred during call second caused by: an error occurred during call first caused by: illegal first.

JLupinExceptionModel class description:

public class JLupinExceptionModel implements Serializable{

    private String              errorMessage;
    private String              errorCode;
    private List<String>        errorReasons;
    private List<String>        errorSolutions;
    private String              sourceStackTrace;
    private Map<String, String> additionalErrorCodeMap;
    private byte []             throwableAsByteArray;

......

Field meaning:
errorMessage – error massage
errorCode – error code (coming from a particular service and a code from a server)
errorReasons – list of reasons for error occurrence. List is available only while using JLupinBaseErrorCodeException
errorSolutions – list of solutions for a given error. List is available only while using JLupinBaseErrorCodeException
sourceStackTrace – stack trace on the server side
additionalErrorCodeMap – map of additional error codes – error in different parts of application may mean different things. List is available only while using JLupinBaseErrorCodeException
throwableAsByteArray
– a given error as serialized board of bites – it is a field used by the proxy interface for JLupin Java Remote Object Invocation protocol when an exception thrown by the service must be also thrown on the part of the client