1
votes

I am writing client-server application on base of int-ip:tcp endpoints. Code written in Kotlin. Application contains two tcp clienst which should make connection to server in sertain sequence, one after each other, when first cleint already establised connection to server and made some initialisation.

As a solution for this synchronisation I suppose to use a SmartLifecycleRoleController to start group of endpoints of a dependent tcp client. To that end in depended (second) client I add role="rcCluster" and auto-startup="false" attributes to tcp-outbound-channel-adapter and tcp-inbound-channel-adapter

<int-ip:tcp-connection-factory id="rcClientConnectionFactory"
                               type="client"
                               host="${tdirelay.host}"
                               port="${tdirelay.rcPort}"
                               single-use="false"
                               so-timeout="10000"
                               so-keep-alive="false"
                               serializer="rawSerializerDeserializer"
                               deserializer="rawSerializerDeserializer"
                               ssl-context-support="sslContext"/>


<int-ip:tcp-outbound-channel-adapter id="rcOutBoundAdapter"
                                     channel="rcPacketQueueChannel"
                                     phase="5000"
                                     connection-factory="rcClientConnectionFactory"
                                     role="rcCluster"
                                     auto-startup="false"
/>


<int-ip:tcp-inbound-channel-adapter id="rcInboundAdapter"
                                    channel="rcFromServer"
                                    client-mode="true"
                                    retry-interval="5000"
                                    connection-factory="rcClientConnectionFactory"
                                    role="rcCluster"
                                    auto-startup="false"


/>  

The leading (first) tcp client uses interceptor endpoint to make a prologue exhange with server in accordance with the protocol:

<bean id="dcInterceptorFactoryChain"
      class="org.springframework.integration.ip.tcp.connection.TcpConnectionInterceptorFactoryChain">
    <property name="interceptors">
        <array>
            <bean class="com.tcpclient.DirectCannel.DCConnectionInterceptorFactory">
            </bean>
        </array>
    </property>
</bean>


<int-ip:tcp-connection-factory id="dcClientConnectionFactory"
                               type="client"
                               host="${tdirelay.host}"
                               port="${tdirelay.dcPort}"
                               single-use="false"
                               so-timeout="10000"
                               so-keep-alive="false"
                               interceptor-factory-chain="dcInterceptorFactoryChain"
                               serializer="rawSerializerDeserializer"
                               deserializer="rawSerializerDeserializer"
                               ssl-context-support="sslContext"
/>

I am planning to call startLifecyclesInRole(String role) and stopLifecyclesInRole(String role) methods of the SmartLifecycleRoleController inside my Interceptor class. So, I added @Autowired private val roleController: SmartLifecycleRoleController to InterceptorFactory as explained in spring-integration/docs

My InterceptorFactory is:

class DCConnectionInterceptorFactory() : TcpConnectionInterceptorFactory, ApplicationEventPublisherAware {

    @Autowired
    private val roleController: SmartLifecycleRoleController? = null

    @Volatile
    private var applicationEventPublisher: ApplicationEventPublisher? = null

    override fun setApplicationEventPublisher(applicationEventPublisher: ApplicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher
    }

    override fun getInterceptor(): TcpConnectionInterceptorSupport {
        return DCConnectionInterceptor(this.applicationEventPublisher!!, roleController!!)
    }
}

IntelliJ IDEA gives warning: Could not autowire. No beans of 'SmartLifecycleRoleController' type found

And building gives error:

[task-scheduler-2] ERROR org.springframework.integration.ip.tcp.connection.ClientModeConnectionManager - Could not establish connection using dcClientConnectionFactory, host=localhost, port=9001 kotlin.KotlinNullPointerException at com.tcpclient.DirectCannel.DCConnectionInterceptorFactory.getInterceptor(DCConnectionInterceptorFactory.kt:25)

I suppose that I need to define SmartLifecycleRoleController type bean in xml configuration file (that is not mentioned in the docs: https://docs.spring.io/spring-integration/docs/4.3.4.RELEASE/reference/html/messaging-endpoints-chapter.html#endpoint-roles). The constructor of this class has arguments: public SmartLifecycleRoleController(List roles, List lifecycles) which I do not know how to fill in my case in xml file:

If you know how to do this, please provide a live example of using bean of the SmartLifecycleRoleController class in the xml configuration file.

1

1 Answers

0
votes

First of all it would be better do not use @Autowired there at all, since it isn't clear if an annotation configuration is enabled in your application context or not. Just because you show only XML config for Spring.

Therefore your DCConnectionInterceptorFactory should have a setter for that roleController property instead. Or what is the proper way to declare Java bean properties in Kotlin...

Then you need to use something like this in your XML config:

<bean class="com.tcpclient.DirectCannel.DCConnectionInterceptorFactory">
    <property name="roleController" ref="integrationLifecycleRoleController"/>
</bean>

The Framework creates for your a SmartLifecycleRoleController automatically and registers it with the mentioned IntegrationContextUtils.INTEGRATION_LIFECYCLE_ROLE_CONTROLLER bean name.

Please, raise a JIRA on the matter to improve documentation to make since much cleaner.

Your approach, by the way, is correct.