<?xml version="1.0" encoding="UTF-8"?>
<!--
  ~~~~~~licensing~~~~~~
  error-handler
  ==========
  Copyright (C) 2020 - 2021 EmDev LLC
  ==========
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at
  
       http://www.apache.org/licenses/LICENSE-2.0
  
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
  ~~~~~~/licensing~~~~~~
  -->

<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0"
           xsi:schemaLocation="
             http://www.osgi.org/xmlns/blueprint/v1.0.0 https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
             ">

    <cm:property-placeholder persistent-id="ru.entaxy.esb.error" update-strategy="reload">
        <cm:default-properties>
            <cm:property name="error.bus.system.id" value="-1"/>
            <cm:property name="error.bus.system.name" value="esb"/>
            <cm:property name="error.bus.always_at_source" value="false"/>
            <cm:property name="error.description.exception_message" value="true"/>
            <cm:property name="error.queue.name" value="error"/>
            <cm:property name="error.system.name" value="error"/>
            <cm:property name="error.stacktrace.show" value="true"/>
            <cm:property name="error.test-route.startup" value="false"/>
        </cm:default-properties>
    </cm:property-placeholder>

    <cm:property-placeholder persistent-id="ru.entaxy.esb.error.code" update-strategy="reload"
                             placeholder-prefix="$errorCode{">
        <cm:default-properties>
            <cm:property name="ru.entaxy.esb.system.common.exception.DefaultException" value="520"/>
        </cm:default-properties>
    </cm:property-placeholder>

    <cm:property-placeholder persistent-id="ru.entaxy.esb.error.text" update-strategy="reload"
                             placeholder-prefix="$errorText{">
        <cm:default-properties>
            <cm:property name="http-520" value="Unknown Error"/>
        </cm:default-properties>
    </cm:property-placeholder>

    <cm:property-placeholder persistent-id="ru.entaxy.esb.error.severity" update-strategy="reload"
                             placeholder-prefix="$errorSeverity{">
        <cm:default-properties>
            <cm:property name="FATAL" value="1"/>
            <cm:property name="ERROR" value="2"/>
            <cm:property name="WARN" value="3"/>
            <cm:property name="INFO" value="4"/>
        </cm:default-properties>
    </cm:property-placeholder>

    <bean id="uuidGenerator" class="java.util.UUID" scope="prototype" factory-method="randomUUID"/>
    <bean id="timestamp" class="ru.entaxy.esb.system.core.common.error.handler.util.Timestamp"/>

    <reference id="pooledConnectionFactory" interface="javax.jms.ConnectionFactory"/>

    <bean id="jms" class="org.apache.camel.component.jms.JmsComponent">
        <property name="connectionFactory" ref="pooledConnectionFactory"/>
    </bean>

    <!--    <bean id="errorProcessor" class="ErrorProcessor"/>-->

    <camelContext id="common-error-handler-context" errorHandlerRef="errorHandlerFailed"
                  xmlns="http://camel.apache.org/schema/blueprint">

        <!--        <errorHandler id="synchronousErrorHandler" redeliveryPolicyRef="noRedelivery"-->
        <!--                      onPrepareFailureRef="errorProcessor"-->
        <!--                      type="DeadLetterChannel" deadLetterUri="direct:syncErrorHandlerEndpoint" />-->
        <errorHandler id="commonErrorHandler" redeliveryPolicyRef="noRedelivery"
                      type="DeadLetterChannel" deadLetterUri="direct-vm:commonErrorEndpoint"/>
        <errorHandler id="errorHandlerFailed" redeliveryPolicyRef="noRedelivery"
                      type="DeadLetterChannel" deadLetterUri="direct:errorHandlerFailedEndpoint"/>
        <errorHandler id="loggingErrorHandler" redeliveryPolicyRef="noRedelivery"/>
        <!--                      type="LoggingErrorHandler" logName="errorHandlerCrash"/>-->
        <redeliveryPolicyProfile id="noRedelivery" disableRedelivery="true"/>

        <route id="error-handler-test-route" errorHandlerRef="commonErrorHandler"
               autoStartup="{{error.test-route.startup}}">
            <from uri="timer:test-route?repeatCount=1"/>
            <log message="error handler test route started successfully\n\n" loggingLevel="INFO"/>

            <setBody>
                <simple>
                    <![CDATA[<packet xmlns="http://www.entaxy.ru/ExchangeTypes/1.0"><content>Oops... some test error occurred</content></packet>]]>
                </simple>
            </setBody>

            <throwException exceptionType="java.lang.IllegalArgumentException" message="Test exception thrown"/>
        </route>

        <!-- the route is designed to handle errors that occurred in other routes of this context  -->
        <route id="error-handler-failed-route" errorHandlerRef="loggingErrorHandler">
            <from uri="direct:errorHandlerFailedEndpoint"/>
            <log message="Exception handled by ${routeId}: ${exception}
                          ${messageHistory}${exception.stacktrace}" loggingLevel="ERROR"/>
            <!--            TODO connect to alarm or monitoring system (send email, sms, etc) -->
        </route>

        <route id="cxf-error-handler-route">
            <from uri="direct-vm:cxfErrorEndpoint"/>
            <log message="Exception handled by ${routeId}: ${header.NTX_ERROR_HANDLER_SoapFault}" loggingLevel="ERROR"/>
            <doTry>
                <to uri="direct-vm:commonErrorEndpoint"/>
                <doFinally>
                    <to uri="xslt:xslt/WrapSoapEnvelope.xsl"/>
                </doFinally>
            </doTry>
        </route>

        <route id="common-error-handler-route">
            <from uri="direct-vm:commonErrorEndpoint"/>
            <log message="Exception handled by ${routeId}: ${exception}
                          on message ${headers.ENTAXY_MessageUUID}
                          ${messageHistory}${exception.stacktrace}" loggingLevel="ERROR"/>

            <setBody>
                <constant><![CDATA[<empty/>]]></constant>
            </setBody>
            <to uri="xslt:xslt/DefaultResponse.xsl"/>
            <to uri="direct:prepareResponseCodeAndTextEndpoint"/>

            <wireTap uri="direct:asynchronousErrorEndpoint"/>
            <to uri="direct:synchronousErrorEndpoint"/>

            <!-- Remove headers before response -->
            <removeHeaders pattern="*"/>
        </route>

        <route id="prepare-response-code-and-text-route">
            <from uri="direct:prepareResponseCodeAndTextEndpoint"/>

            <choice>
                <when>
                    <simple>${exception} != null</simple>
                    <setHeader name="NTX_ERROR_HANDLER_ExceptionClass">
                        <simple resultType="String">${exception.class.name}</simple>
                    </setHeader>
                    <setHeader name="NTX_ERROR_HANDLER_ExceptionMessage">
                        <simple resultType="String">${exception.message}</simple>
                    </setHeader>
                </when>
                <when>
                    <simple>${header.NTX_ERROR_HANDLER_SoapFault} != null</simple>
                    <setHeader name="NTX_ERROR_HANDLER_ExceptionClass">
                        <simple resultType="String">${header.NTX_ERROR_HANDLER_SoapFault.cause.class.name}</simple>
                    </setHeader>
                    <setHeader name="NTX_ERROR_HANDLER_ExceptionMessage">
                        <simple resultType="String">${header.NTX_ERROR_HANDLER_SoapFault.cause.message}</simple>
                    </setHeader>
                </when>
                <otherwise>
                    <setHeader name="NTX_ERROR_HANDLER_ExceptionClass">
                        <simple resultType="String">ru.entaxy.esb.system.common.exception.DefaultException</simple>
                    </setHeader>
                    <setHeader name="NTX_ERROR_HANDLER_ExceptionMessage">
                        <simple resultType="String">Something wrong</simple>
                    </setHeader>
                </otherwise>
            </choice>
            <choice>
                <when>
                    <simple>${header.NTX_ERROR_HANDLER_ExceptionClass}</simple>
                    <doTry>
                        <setHeader name="NTX_ERROR_HANDLER_ResponseCode">
                            <simple>${properties:${header.NTX_ERROR_HANDLER_ExceptionClass}}</simple>
                        </setHeader>
                        <doCatch>
                            <exception>java.lang.Exception</exception>
                            <setHeader name="NTX_ERROR_HANDLER_ResponseCode">
                                <simple>${properties:ru.entaxy.esb.system.common.exception.DefaultException}</simple>
                            </setHeader>
                        </doCatch>
                    </doTry>
                </when>
            </choice>
            <choice>
                <when>
                    <simple>${properties:error.description.exception_message} == "true"</simple>
                    <setHeader name="NTX_ERROR_HANDLER_ResponseText">
                        <simple>${header.NTX_ERROR_HANDLER_ExceptionMessage}</simple>
                    </setHeader>
                </when>
                <otherwise>
                    <setHeader name="NTX_ERROR_HANDLER_ResponseText">
                        <simple>${properties:${header.NTX_ERROR_HANDLER_ResponseCode}}</simple>
                    </setHeader>
                </otherwise>
            </choice>
            <choice>
                <when>
                    <simple>
                        ${properties:error.stacktrace.show} == "true"
                        &amp;&amp; ${exception.stacktrace} != null
                    </simple>
                    <setHeader name="NTX_ERROR_HANDLER_Stacktrace">
                        <simple>${exception.stacktrace}</simple>
                    </setHeader>
                </when>
            </choice>

            <log message="${exchangeProperty.CamelExceptionCaught}\n" loggingLevel="DEBUG"/>
            <log message="${routeId}: \n
                 ${header.NTX_ERROR_HANDLER_ExceptionClass} \n
                 ${header.NTX_ERROR_HANDLER_ResponseCode} ${header.NTX_ERROR_HANDLER_ResponseText}"
                 loggingLevel="INFO"/>
        </route>

        <route id="asynchronous-error-handler-route">
            <from uri="direct:asynchronousErrorEndpoint"/>
            <log message="${routeId}" loggingLevel="DEBUG"/>

            <to uri="direct:prepareErrorPacketEndpoint"/>
            <removeHeaders pattern="NTX_ERROR_HANDLER_.+"/>

            <!-- Send error packet to central error handling system -->
            <doTry>
                <toD uri="system:${properties:error.system.name}?exchangePattern=InOnly"/>
                <doCatch>
                    <exception>java.lang.Exception</exception>
                    <log message="${exception.message}" loggingLevel="ERROR"/>
                    <log message="${exception.stacktrace}" loggingLevel="DEBUG"/>
                    <toD uri="jms:queue:entaxy.${properties:error.queue.name}?exchangePattern=InOnly"/>
                </doCatch>
            </doTry>

            <!-- Send error packet back to the calling system -->
            <choice>
                <when>
                    <simple>${headers.X-SystemName} != "esb"</simple>
                    <doTry>
                        <toD uri="system:${headers.X-SystemName}?exchangePattern=InOnly"/>
                        <doCatch>
                            <exception>java.lang.Exception</exception>
                            <log message="Can't deliver error packet to system: ${headers.X-SystemName}"
                                 loggingLevel="ERROR"/>
                            <log message="${exception.message}" loggingLevel="ERROR"/>
                            <log message="${exception.stacktrace}" loggingLevel="DEBUG"/>
                        </doCatch>
                    </doTry>
                </when>
            </choice>
        </route>

        <route id="prepare-error-packet-route">
            <from uri="direct:prepareErrorPacketEndpoint"/>
            <log message="${routeId}" loggingLevel="DEBUG"/>
            <to uri="direct:prepareErrorPacketHeadersEndpoint"/>

            <setHeader name="ENTAXY_Source">
                <constant>esb</constant>
            </setHeader>

            <log message="Before transformation \n${body}" loggingLevel="DEBUG"/>
            <to uri="xslt:xslt/UniversalErrorPacket.xsl"/>
            <log message="After transformation \n${body}" loggingLevel="DEBUG"/>

            <setHeader name="ENTAXY_MessageUUID">
                <simple>${bean:uuidGenerator.toString}</simple>
            </setHeader>
            <setHeader name="ENTAXY_MessageType">
                <constant>ВыгрузкаДанныхКаноническийФормат</constant>
            </setHeader>
            <setHeader name="ENTAXY_ContentType">
                <constant>application/xml</constant>
            </setHeader>
            <setHeader name="CamelJms_IntMessageType">
                <constant>String</constant>
            </setHeader>
            <setHeader name="CamelJms_IntContentXsiType">
                <constant>xs:string</constant>
            </setHeader>
        </route>

        <route id="prepare-error-packet-headers-route">
            <from uri="direct:prepareErrorPacketHeadersEndpoint"/>

            <setHeader name="NTX_ERROR_HANDLER_CentralIntegrationDB">
                <simple>${properties:error.system.name}</simple>
            </setHeader>

            <choice>
                <when>
                    <simple>${headers.ENTAXY_Source} != null &amp;&amp; ${headers.ENTAXY_Source} != ""
                    </simple>
                    <setHeader name="NTX_ERROR_HANDLER_Source">
                        <simple>${headers.ENTAXY_Source}</simple>
                    </setHeader>
                    <setHeader name="NTX_ERROR_HANDLER_Destination">
                        <simple>${headers.ENTAXY_Source}</simple>
                    </setHeader>
                </when>
                <when>
                    <simple>${headers.NTX_SystemId} != null &amp;&amp; ${headers.NTX_SystemId} != ""</simple>
                    <setHeader name="NTX_ERROR_HANDLER_Source">
                        <simple>${headers.NTX_SystemId}</simple>
                    </setHeader>
                    <setHeader name="NTX_ERROR_HANDLER_Destination">
                        <simple>${headers.NTX_SystemId}</simple>
                    </setHeader>
                </when>
                <when>
                    <simple>${headers.X-SystemName} != null &amp;&amp; ${headers.X-SystemName} != ""</simple>
                    <setHeader name="NTX_ERROR_HANDLER_Source">
                        <simple>${headers.X-SystemName}</simple>
                    </setHeader>
                    <setHeader name="NTX_ERROR_HANDLER_Destination">
                        <simple>${headers.X-SystemName}</simple>
                    </setHeader>
                </when>
                <otherwise>
                    <setHeader name="NTX_ERROR_HANDLER_Source">
                        <constant>esb</constant>
                    </setHeader>
                    <setHeader name="X-SystemName">
                        <constant>esb</constant>
                    </setHeader>
                </otherwise>
            </choice>
            <choice>
                <when>
                    <simple>${headers.X-SystemName} == null || ${headers.X-SystemName} == ""</simple>
                    <setHeader name="X-SystemName">
                        <constant>esb</constant>
                    </setHeader>
                </when>
            </choice>
            <choice>
                <when>
                    <simple>${headers.X-SystemId} == null || ${headers.X-SystemId} == ""</simple>
                    <setHeader name="X-SystemId">
                        <constant>-1</constant>
                    </setHeader>
                </when>
            </choice>
            <choice>
                <when>
                    <simple>${properties:error.bus.always_at_source} == "true"</simple>
                    <setHeader name="NTX_ERROR_HANDLER_Source">
                        <constant>esb</constant>
                    </setHeader>
                    <setHeader name="X-SystemName">
                        <constant>esb</constant>
                    </setHeader>
                    <setHeader name="X-SystemId">
                        <constant>-1</constant>
                    </setHeader>
                </when>
            </choice>

            <setHeader name="NTX_ERROR_HANDLER_ErrorUUID">
                <simple>${bean:uuidGenerator.toString}</simple>
            </setHeader>
            <log message="Prepare error packet with eventUUID: ${headers.NTX_ERROR_HANDLER_ErrorUUID}"
                 loggingLevel="ERROR"/>
            <setHeader name="NTX_ERROR_HANDLER_Timestamp">
                <simple>${bean:timestamp?method=currentTimeMillis}</simple>
            </setHeader>
            <when>
                <simple>${headers.NTX_ERROR_HANDLER_SeverityLevel} == null</simple>
                <setHeader name="NTX_ERROR_HANDLER_SeverityLevel">
                    <constant>ERROR</constant>
                </setHeader>
            </when>
        </route>

        <route id="synchronous-error-handler-route">
            <from uri="direct:synchronousErrorEndpoint"/>
            <setBody>
                <constant><![CDATA[<root/>]]></constant>
            </setBody>

            <choice>
                <when>
                    <simple>${headers.NTX_ERROR_HANDLER_GenerateResponseEndpoint} != null</simple>
                    <toD uri="direct-vm:${headers.NTX_ERROR_HANDLER_GenerateResponseEndpoint}"/>
                </when>
                <when>
                    <simple>${headers.operationName}</simple>
                    <doTry>
                        <toD uri="xslt:xslt/operation/${header.operationName}.xsl"/>
                        <doCatch>
                            <exception>java.lang.Exception</exception>
                            <log message="${exception}" loggingLevel="ERROR"/>
                            <to uri="xslt:xslt/DefaultResponse.xsl"/>
                        </doCatch>
                    </doTry>
                </when>
                <otherwise>
                    <to uri="xslt:xslt/DefaultResponse.xsl"/>
                </otherwise>
            </choice>
        </route>

    </camelContext>

</blueprint>
