KotlinでASTERIA Warpのカスタムコンポーネントを作成する

# はじめに
ASTERIA Warpでは、独自のカスタムコンポーネントを作成することができます。そのために必要なファイル一式は、JavaInterpreterコンポーネントのメニューから作成します。出力されるソースコードは、Javaで書かれており、基本的にはそのままJavaで行いたい処理を書くことになります。しかしながら、Androidアプリ開発などでKotlinに慣れていると、Kotlinの方がJavaより断然書きやすかったりします。
そこで、この記事では、Kotlinを使ってカスタムコンポーネントを作成する方法を紹介します。

# 環境
* Windows 10
* ASTERIA Warp 2016
* Ant 1.10.12

# Kotlinコンパイラのダウンロード
[こちら](https://github.com/JetBrains/kotlin/releases)からコンパイラのzipファイルをダウンロードします。ダウンロードできたら解凍して、kotlincフォルダを任意の場所に置いて下さい。

# カスタムコンポーネントのファイル作成
JavaInterpreterコンポーネントのメニューから「カスタムコンポーネントの作成」を実行してファイルを作成します。この記事では説明は省略します。詳しい作成手順は、公式ドキュメントを参照して下さい。

https://help.asteria.com/documentation/warp/ja/2106/flow/sdk/guide/ToolGuide.html

# ソースファイルの修正
## Kotlinへの変換
Javaで書かれているコンポーネントのクラスファイルをKotlinに書き換えます。統合開発環境のIntelliJ IDEAには、JavaからKotlinに変換する機能があるので、使えば楽にできます。
以下は、変換したコード例です。

```kotlin
class KotlinComponent : SimpleComponent() {
    override fun getComponentName(): String {
        return COMPONENT_NAME
    }

    @Throws(FlowException::class)
    override fun execute(context: ExecuteContext): Boolean {
        val result = doExecute(context, this)
        val factory = outputConnector.streamFactory
        val os: StreamDataObject = when (result) {
            null -> factory.createEmptyStream()
            is ByteArray -> factory.create(result)
            is String -> if (factory is StreamFactoryText) factory.create(result) else throw ComponentException("Invalid return value: $result")
            is StreamDataObject -> if (factory.type == result.type) result else throw ComponentException("Invalid return value: $result")
            is Document -> if (factory is StreamFactoryXML) factory.create(result) else throw ComponentException("Invalid return value: $result")
            else -> throw ComponentException("Invalid return value: $result")
        }
        setOutputStream(os)
        return true
    }

    @Throws(FlowException::class)
    private fun doExecute(context: ExecuteContext, component: KotlinComponent): Any {
        return "Kotlin"
    }

    @Throws(LicenseException::class)
    override fun checkLicense() {
        // ライセンスチェックを行う場合はここにライセンスチェック処理を記述します。
        // getFlowlibPath() で [install dir]/flow/lib/flowlib フォルダーのパスが取得できます。
    }

    // Utility Method
    fun getParameter(name: String?): Value? {
        val prop = getProperty(name)
        return if (prop is ValueProperty) prop.value else null
    }

    public override fun getInputConnector(): InputConnector {
        return super.getInputConnector()
    }

    public override fun getOutputConnector(): OutputConnector {
        return super.getOutputConnector()
    }

    @Throws(StreamException::class)
    public override fun setOutputStream(stream: StreamDataObject) {
        super.setOutputStream(stream)
    }

    @Throws(StreamException::class)
    public override fun setOutputStream(stream: StreamDataObject, isSetProperties: Boolean) {
        super.setOutputStream(stream, isSetProperties)
    }

    companion object {
        const val COMPONENT_NAME = "KotlinComponent"
    }

    init {
        val ia = StreamType.ALL
        val oa = StreamType.TEXT
        inputConnector.acceptType = ia
        inputConnector.acceptLinkCount = 1
        outputConnector.acceptType = oa
    }
}
```

## build.xmlの修正
KotlinファイルをコンパイルできるようにAntのbuild.xmlを以下のように修正します。`kotlin-ant.jar`のパスは、ダウンロードしたKotlinコンパイラのパスを指定して下さい。（この例では、C直下にkotlincフォルダを置いています。）


```diff_xml
 <project name="KotlinComponent" default="dist" basedir=".">
+	<typedef resource="org/jetbrains/kotlin/ant/antlib.xml" classpath="C:/kotlinc/lib/kotlin-ant.jar"/>

	中略

	<!--
	  Javaソースファイルのコンパイルタスク
	  -->
	<target name="compile">
		<mkdir dir="${classes.dest.dir}"/>
		<mkdir dir="${dist.dir}"/>
		<javac srcdir="${sources.src.dir}" destdir="${classes.dest.dir}" debug="off" encoding="utf-8">
			<classpath>
				<fileset dir="${designer.lib}">
					<include name="**/*.jar"/>
				</fileset>
			</classpath>
+			<withKotlin/>
		</javac>
		<copy todir="${classes.dest.dir}">
			<fileset dir="${sources.src.dir}">
				<patternset refid="resource-files"/>
			</fileset>
		</copy>
	</target>
```

# ビルド
build.xmlがあるフォルダ内で、`ant`を実行します。ビルドが完了するとdistフォルダにjarファイルが作成されます。
作成されたjarファイルは、`[DATA_DIR]/system/lib/components`にコピーします。さらに、`kotlinc/lib`内の`kotlin-stdlib.jar`を`[DATA_DIR]/system/lib/userlib`にコピーする必要があります。（[DATA_DIR]は、フローサービスのデータフォルダです。Windowsのデフォルトは、`C:/asteriahome5`です。）
これで、フローサービスを再起動すれば、作成したコンポーネントを使用することができます。

# おわりに
Kotlinでカスタムコンポーネントを作成する方法を紹介しました。ただ、正式にサポートしているわけではないので、試す場合は自己責任でお願いします。