インターセプタを設定したTcpConnectionが発行するTcpConnectionOpenEventのコネクションファクトリ名がunknownになる件が修正されます

#### 確認環境
- Java 8
- STS 3.9.1.RELEASE
- Spring Framework 4.3.13
- Spring Integration 4.3.12

### どういう問題?
#### おおまかなTCP/IP通信の仕組み
`Spring Integration`ではTCP/IP通信をサポートしていて、`TcpIn/OutboundGateway`や、`In/OutboundChannelAdapter`が通信の窓口として用意され、それぞれに`ConnectionFactory`に紐づけられています。通信が必要になった場合、窓口となる`Gateway`または`Adapter`が`ConnectionFactory`から`TcpConnection`インスタンスを生成し通信します。

#### インターセプタとは?
通信する際に、ログ出力など、なんらかの処理を挟み込みたい場合は、`ConnectionFactory`の`InterceptorFactoryChain`プロパティに`TcpConnectionInterceptorSupport`を継承したクラスのインスタンスを返す`TcpConnectionInterceptorFactory`クラスを指定します。以下は実装例です。

```java:TcpConnectionInterceptorSupportを継承したクラス
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.integration.ip.tcp.connection.TcpConnectionInterceptorSupport;
import org.springframework.messaging.Message;

public class SimpleInterceptor extends TcpConnectionInterceptorSupport {

	private static final Logger logger = LoggerFactory.getLogger(SimpleInterceptor.class);
	
	public SimpleInterceptor(ApplicationEventPublisher publisher) {
		super(publisher);
	}

	@Override
	public void send(Message<?> message) throws Exception {
		// メッセージ送信前にログ出力処理を挟み込む
		logger.debug("send message via interceptor");
		super.send(message);
	}
}
```
```java:TcpConnectionInterceptorSupportを継承したクラスのインスタンスを返すTcpConnectionInterceptorFactory
import org.springframework.context.support.ApplicationObjectSupport;
import org.springframework.integration.ip.tcp.connection.TcpConnectionInterceptorFactory;
import org.springframework.integration.ip.tcp.connection.TcpConnectionInterceptorSupport;

public class SimpleInterceptorFactory extends ApplicationObjectSupport implements TcpConnectionInterceptorFactory {

	public SimpleInterceptorFactory() {
	}

	@Override
	public TcpConnectionInterceptorSupport getInterceptor() {
		return new SimpleInterceptor(getApplicationContext());
	}
}
```

```xml:bean定義ファイル
<int-ip:tcp-connection-factory id="client1"
	type="client" host="localhost" port="${availableServerSocket1}"
	single-use="true" interceptor-factory-chain="interceptorFactoryChain" />
<bean id="interceptorFactoryChain"
	class="org.springframework.integration.ip.tcp.connection.TcpConnectionInterceptorFactoryChain">
	<property name="interceptors">
		<array>
			<bean
				class="com.neriudon.example.tcp.interceptor.SimpleInterceptorFactory" />
		</array>
	</property>
</bean>
```

#### 何が問題なの?
`ConnectionFactory`が`TcpConnection`を生成し`Socket`レベルでの接続が確立されるタイミングで`TcpConnectionOpenEvent`を発行しますが、`ConnectionFactory`にインターセプタを設定していると、`connectionfactoryname`プロパティが初期値である`unknown`のままになります。
以下はインターセプタを設定した場合と設定していない場合のログ出力結果の比較です。

```
インターセプタを設定した場合
11:58:32.397 [main] DEBUG com.neriudon.example.tcp.listener.TcpConnectionEventsListener - ★OPEN★ TcpConnectionOpenEvent [source=SimpleInterceptor:null], [factory=unknown, connectionId=localhost:50001:58459:aa1f25b0-570e-4631-8477-33a19f1bb6ba] **OPENED**
インターセプタを設定していない場合
11:58:32.434 [main] DEBUG com.neriudon.example.tcp.listener.TcpConnectionEventsListener - ★OPEN★ TcpConnectionOpenEvent [source=TcpNetConnection:localhost:50002:58460:a92051dd-9003-4563-be59-3675dee3112d], [factory=client2, connectionId=localhost:50002:58460:a92051dd-9003-4563-be59-3675dee3112d] **OPENED**
```

#### この問題が発生する理由と改善策
`TcpConnectionInterceptorSupport`クラスに`ConnectionFactoryName`を設定する処理がないのが原因です。が、`ConnectionFactory`の情報は実際に通信をする`TcpConnection`が持っているので、`ConnectionFactoryName`を返す時に`TcpConnectionInterceptorSupport`が`TcpConnection`の`ConnectionFactoryName`を返すようにすれば:ok_hand:。詳しくは下記のPRのリンクを参照してください。
ちなみに他の`TcpConnectionEvent`は元々`TcpConnectionInterceptorSupport`が`TcpConnection`の処理を呼び出すよう設計されているので問題ありません。

#### この問題による影響は?
ほとんど無いです:stuck_out_tongue_winking_eye:。
`TcpConnectionInterceptorSupport`がmasterに取り込まれたのが2016年3月で、それからバグ報告がされなかったのと、`TcpConnectionOpenEvent`自体が`Spring Integration`の[ドキュメント](https://docs.spring.io/spring-integration/docs/4.3.13.RELEASE/reference/html/ip.html#tcp-events)でも浅く書かれているので、この問題がプロジェクトに深刻な影響を与えてはいないでしょう。

#### いつ修正されるの?
リリースされる日付は分かりませんが、[JIRA](https://jira.spring.io/browse/INT-4378)を見る限り、次の5.0.1, 4.3.14で修正されます。2018年1月15日時点で[PR](https://github.com/spring-projects/spring-integration/pull/2326)が出されているので、近々マージされるでしょう。

### この記事を投稿するに至った経緯 
この件について[stackoverflow](https://stackoverflow.com/questions/48238185/tcpconnection-wrapped-interceptor-publish-tcpconnectionopenevent-whose-connectio)で質問したのが私だからです:stuck_out_tongue_closed_eyes:。
`Spring Integration`プロジェクトでは、使い方や仕様に関する質問は`spring-integration`タグを付けてstackoverflowで質問するルールになっています。私はバグか仕様なのか判断がつかなかったので、[サンプルアプリ](https://github.com/neriudon/si_tcp_sample)を作成したうえで、発生する条件やログを提示したところ、中の人からバグですと回答がありました。
しかし、もたもたしてるうちに中の人がJIRAに起票してしまったので、初のOSSへのバグ報告できなくて残念:confounded:。

1/30 追記：
今回の修正を取り込んだ[4.3.14.RELEASE](https://github.com/spring-projects/spring-integration/releases/tag/v4.3.14.RELEASE)および[5.0.1.RELEASE](https://github.com/spring-projects/spring-integration/releases/tag/v5.0.1.RELEASE)がリリースされました:v:。