<?xml version="1.0" encoding="UTF-8"?>
<!--
  ~~~~~~licensing~~~~~~
  events-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://osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">

    <cm:property-placeholder persistent-id="ru.entaxy.esb" update-strategy="reload" placeholder-prefix="$common{">
        <cm:default-properties>
            <cm:property name="org.quartz.jobStore.driverDelegateClass"
                         value="org.quartz.impl.jdbcjobstore.PostgreSQLDelegate"/>
        </cm:default-properties>
    </cm:property-placeholder>

    <cm:property-placeholder
            persistent-id="ru.entaxy.esb.system.event.handler" update-strategy="reload">
        <cm:default-properties>
            <cm:property name="quartz.job.clean.cron" value="0+0/1+*+*+*+?+*"/><!-- cron - Every minute -->
            <cm:property name="mode.dev" value="false"/>
        </cm:default-properties>
    </cm:property-placeholder>

    <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="eventHelper" class="ru.entaxy.esb.system.core.events.handler.util.EventHelper"/>

    <bean id="propertiesHelper" class="ru.entaxy.esb.system.common.util.PropertiesHelper">
        <argument index="0" type="java.lang.String" value="ru.entaxy.esb.system.event.handler.cfg"/>
        <argument index="1" type="boolean" value="true"/>
    </bean>

    <bean id="subscriptionProcessingGenerator"
          class="ru.entaxy.esb.system.core.events.handler.SubscriptionProcessingGenerator">
        <property name="connectionFactory" ref="pooledConnectionFactory"/>
        <property name="eventHelper" ref="eventHelper"/>
        <property name="propertiesHelper" ref="propertiesHelper"/>
    </bean>

    <bean id="eventAdminHelper" class="ru.entaxy.esb.system.core.events.handler.util.EventAdminHelper"/>

    <reference id="systemSubscriptionService"
               interface="ru.entaxy.esb.system.core.events.jpa.SystemSubscriptionService"
               timeout="30000"
               availability="mandatory"/>

    <reference id="eventTopicService"
               interface="ru.entaxy.esb.system.core.events.jpa.EventTopicService"
               timeout="30000"
               availability="mandatory"/>

    <bean id="gson" class="ru.entaxy.esb.system.core.events.handler.util.GsonDataFormatInitializer">
        <property name="fieldNamingPolicy" value="LOWER_CASE_WITH_UNDERSCORES"/>
    </bean>

    <bean id="quartz" class="org.apache.camel.component.quartz.QuartzComponent">
        <property name="schedulerFactory" ref="factory"/>
    </bean>

<!--    NOTE: Don't delete! -->
<!--    It needs for quartz because dataSource doesn't has time to registry in jndi-->
    <reference id="cache" interface="javax.sql.DataSource" filter="(osgi.jndi.service.name=entaxy.esb.cache)"
               availability="mandatory"/>

    <bean id="factory" class="org.quartz.impl.StdSchedulerFactory">
        <argument>
            <props>
                <prop key="org.quartz.scheduler.instanceName">entaxy</prop>
                <prop key="org.quartz.scheduler.instanceId">AUTO</prop>
                <prop key="org.quartz.scheduler.skipUpdateCheck">true</prop>

                <prop key="org.quartz.jobStore.driverDelegateClass">$common{org.quartz.jobStore.driverDelegateClass}
                </prop>
                <prop key="org.quartz.jobStore.isClustered">true</prop>
                <prop key="org.quartz.jobStore.clusterCheckinInterval">5000</prop>
                <prop key="org.quartz.jobStore.class">org.quartz.impl.jdbcjobstore.JobStoreTX</prop>
                <prop key="org.quartz.jobStore.dataSource">cache</prop>
                <prop key="org.quartz.dataSource.cache.jndiURL">osgi:service/entaxy.esb.cache</prop>

                <prop key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop>
                <prop key="org.quartz.threadPool.threadCount">1</prop>
            </props>
        </argument>
    </bean>


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

        <route id="handlerInit" autoStartup="true">
            <from uri="timer:handlerInit?repeatCount=1"/>
            <to uri="bean:systemSubscriptionService?method=listByDeleted(false)"/>

            <bean ref="subscriptionProcessingGenerator" method="construct(${exchange})"/>
        </route>

        <route id="prepareSubscriberConsumer">
            <from uri="direct-vm:prepareSubscriberConsumer"/>

            <bean beanType="java.util.Collections"
                  method="singletonList(ru.entaxy.esb.system.core.events.jpa.entity.SystemSubscription)"/>

            <to uri="direct:subscriptionNotifyCluster"/>
        </route>

        <route id="prepareSubscriberRoute">
            <from uri="direct-vm:prepareSubscriberRoute"/>
            <bean beanType="java.util.Collections"
                  method="singletonList(ru.entaxy.esb.system.core.events.jpa.entity.SystemSubscription)"/>
            <to uri="direct-vm:prepareSubscriberRoutes"/>
        </route>

        <route id="prepareSubscriberRoutes">
            <from uri="direct-vm:prepareSubscriberRoutes"/>

            <setProperty name="subscribe">
                <simple resultType="boolean">true</simple>
            </setProperty>

            <to uri="direct:subscriptionNotifyCluster"/>
        </route>

        <route id="deleteSubscriberConsumer">
            <from uri="direct-vm:deleteSubscriberConsumer"/>

            <bean beanType="java.util.Collections"
                  method="singletonList(ru.entaxy.esb.system.core.events.jpa.entity.SystemSubscription)"/>

            <setProperty name="bodyHolder">
                <simple>${body}</simple>
            </setProperty>

            <to uri="direct:subscriptionNotifyCluster"/>

            <setBody>
                <simple>${exchangeProperty.bodyHolder}</simple>
            </setBody>

            <bean ref="subscriptionProcessingGenerator" method="destruct(${exchange})"/>
        </route>

        <route id="deleteSubscriberConsumers">
            <from uri="direct-vm:deleteSubscriberConsumers"/>

            <setProperty name="bodyHolder">
                <simple>${body}</simple>
            </setProperty>

            <to uri="direct:subscriptionNotifyCluster"/>

            <setBody>
                <simple>${exchangeProperty.bodyHolder}</simple>
            </setBody>

            <bean ref="subscriptionProcessingGenerator" method="destruct(${exchange})"/>
        </route>

        <route id="deleteSubscriberRoute">
            <from uri="direct-vm:deleteSubscriberRoute"/>
            <bean beanType="java.util.Collections"
                  method="singletonList(ru.entaxy.esb.system.core.events.jpa.entity.SystemSubscription)"/>
            <to uri="direct-vm:deleteSubscriberRoutes"/>
        </route>

        <route id="deleteSubscriberRoutes">
            <from uri="direct-vm:deleteSubscriberRoutes"/>

            <setProperty name="subscribe">
                <simple resultType="boolean">false</simple>
            </setProperty>

            <to uri="direct:subscriptionNotifyCluster"/>
        </route>

        <route id="deleteSubscriberQueues">
            <from uri="direct-vm:deleteSubscriberQueues"/>

            <bean ref="subscriptionProcessingGenerator" method="destruct(${exchange})"/>
        </route>

        <route id="subscriptionNotifyCluster">
            <from uri="direct:subscriptionNotifyCluster"/>
            <log message="SEND subscription event" loggingLevel="TRACE"/>
            <marshal>
                <custom ref="gson"/>
            </marshal>

            <bean ref="eventAdminHelper" method="setProperty('subscribe', ${exchangeProperty.subscribe})"/>
            <bean ref="eventAdminHelper" method="setProperty('subscriptions', ${body})"/>
            <bean ref="eventAdminHelper" method="createEvent('subscription')"/>

            <to uri="eventadmin:subscription"/>
        </route>

        <route id="handleConsumerRoutes">
            <from uri="eventadmin:subscription"/>

            <log message=">>>RECEIVE subscription event" loggingLevel="TRACE"/>

            <setProperty name="subscribe">
                <simple resultType="boolean">${body.getProperty('subscribe')}</simple>
            </setProperty>

            <setBody>
                <simple resultType="String">${body.getProperty('subscriptions')}</simple>
            </setBody>

            <log message=">>>RECEIVE subscription ${body}" loggingLevel="TRACE"/>

            <unmarshal>
                <custom ref="gson"/>
            </unmarshal>

            <choice>
                <when>
                    <simple>${exchangeProperty.subscribe}</simple>
                    <bean ref="subscriptionProcessingGenerator" method="construct(${exchange})"/>
                </when>
                <otherwise>
                    <bean ref="subscriptionProcessingGenerator" method="destructRoute(${exchange})"/>
                </otherwise>
            </choice>
        </route>

        <route id="cleanTopicsJob">
            <from uri="quartz://cleanTopics?cron={{quartz.job.clean.cron}}"/>
            <log message="Job: Clean topics and subscriptions" loggingLevel="DEBUG"/>
            <to uri="direct-vm:cleanProcess"/>
        </route>

        <route id="cleanProcess">
            <from uri="direct-vm:cleanProcess"/>

            <to uri="bean:systemSubscriptionService?method=listByDeleted(true)"/>

            <to uri="direct-vm:deleteSubscriberConsumers"/>

            <to uri="bean:eventTopicService?method=clean"/>


            <log message="CleanProcess: Deleted ${body} topics" loggingLevel="TRACE"/>
        </route>

    </camelContext>

</blueprint>
