Watson Language Translator を Java で呼び出す。編集中の Notes 文書から使う。

Watson Language Translator は、IBMが提供する機械翻訳アプリケーションです。
今回は、編集中の Notes 文書から Java を使って呼び出し、翻訳結果を 編集中の Notes 文書の別フィールドに戻したいと思います。
Java からの呼び出しが API リファレンス 通りではなかったので、Notes を使わわない方にも参考になると思います。
なお、編集中の Notes 文書から呼び出すために LS2J を使いました。

# Watson Language Translator は、IBMが提供する機械翻訳アプリケーションです。
[Watson Language Translator](https://www.ibm.com/watson/jp-ja/developercloud/language-translator.html) は、IBM が提供する Watson サービスの一つです。
[IBM Cloudライト・アカウント (Bluemix)](https://www.ibm.com/cloud-computing/jp/ja/bluemix/lite-account/)無期限・無料で使えるようになりました。

# Watson Language Translator を Java で呼び出す。
## Java から Watson を使いたいときは watson-developer-cloud/java-sdk があります。
GitHub に [watson-developer-cloud/java-sdk](https://github.com/watson-developer-cloud/java-sdk) のページがあります。
この SDK を使えば低レベルの http リクエストや json のパースを、自分で処理する必要がなくなります。
中ほどにある下記の [here](https://github.com/watson-developer-cloud/java-sdk/releases/download/java-sdk-4.0.0/java-sdk-4.0.0-jar-with-dependencies.jar) のリンクからすべての Watson サービス用の SDK が依存先も含めたひとつの jar としてダンロードできます。

```
JAR

Download the jar with dependencies here.
```

現在のファイル名は java-sdk-4.0.0-jar-with-dependencies.jar と Ver 4.0 が提供されています。

## API リファレンス通りに動きません。

Java から翻訳を呼びだす方法は、API リファレンスでは[ここ](https://www.ibm.com/watson/developercloud/language-translator/api/v2/?java#translate)にあります。
このようなサンプルが示されています。

```
LanguageTranslator service = new LanguageTranslator();
service.setUsernameAndPassword("{username}","{password}");

TranslateOptions translateOptions = new TranslateOptions.Builder()
  .text("hello")
  .source(Language.ENGLISH)
  .target(Language.SPANISH)
  .build();

TranslationResult result = service.translate(translateOptions)
  .execute();

System.out.println(result);
``` 

String を入力すれば toString を利用できる TranslationResult が返ってくることを期待させるコード例です。
しかし、実際は、こんなに単純ではありませんでした。

## 動くJava コードはこちら
色々調べて動くようになった Java コードはこちらです。翻訳前の文章は List で渡します。結果も TranslationResult から List で取り出します。
翻訳を実行するだけのユーティリティクラスなので翻訳を実行するメソッド  doIt() はインスタンス化が不要な static にしました。日本語の文を String で渡すと、英語の文が String で返ってきます。

```
import com.ibm.watson.developer_cloud.language_translator.v2.*;
import com.ibm.watson.developer_cloud.language_translator.v2.model.*;
import com.ibm.watson.developer_cloud.language_translator.v2.util.*;
import java.util.*;

public class WatsonTran {

    public static void main (String[] args) {
        System.out.println(doIt(args[0]));
    }

    public static String doIt(String input) {
        String output = "";
        List<String> inputList = new ArrayList<String>(Arrays.asList(input));

        LanguageTranslator service = new LanguageTranslator();
        service.setUsernameAndPassword("{username}","{password}");

        TranslateOptions translateOptions = new TranslateOptions.Builder()
          .text(inputList)
          .source(Language.JAPANESE)
          .target(Language.ENGLISH)
          .build();

        TranslationResult outputTran = service.translate(translateOptions)
          .execute();

        List<Translation> translations = outputTran .getTranslations();

        if (translations.size() > 0) {
            for (Translation nextTranslation : translations) {
                output += nextTranslation.getTranslation();
            }
        }

        return output;
    }
}
```

実行結果はこちら。「こんにちは世界」が「hello world」に翻訳されました。

```
C:\watson>java -cp java-sdk-4.0.0-jar-with-dependencies.jar;. WatsonTran こんにちは世界
12 05, 2017 10:17:28 午前 okhttp3.internal.platform.Platform log
情報: --> POST https://gateway.watsonplatform.net/language-translator/api/v2/translate http/1.1 (62-byte body)
12 05, 2017 10:17:28 午前 okhttp3.internal.platform.Platform log
情報: <-- 200 OK https://gateway.watsonplatform.net/language-translator/api/v2/translate (211ms, unknown-length body)
hello world
```

# 編集中の Notes 文書から使う。
今回作りたいアプリケーションは、あるフィールドに日本語に入力してアクションすると、別のフィールドに翻訳文が自動的にはいるというものです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/184930/9b91652c-f6fc-dbe2-58c4-e4a75dd22e8f.png)

## どうやって Notes から Java を呼ぶか?

今回の悩みどころは、どうやって Notes から Java を呼ぶかという点です。
編集中文書のフィールドの値を渡し、編集中文書のフィールドに値を戻したいのです。

### Java Agent では編集中の文書のアクセスできません。
Notes 内で Java を呼び出すもっとも一般的な方法は Java Agent を使うことです。しかし、Java Agent では編集中の文書のアクセスできませんので、今回の目的には使えません。
いつも参考にさせていただく [まだプログラマーですが何か？](まだプログラマーですが何か？) に [ノーツでワトソンを体験！](http://dotnsf.blog.jp/archives/1058300568.html) という記事があります。
何に関する文章かを分類する Natural Language Classifier(NLC) をNotesから使うことを例にしています。こちらでは Java Agent を利用しています。
トレーニング(これは、全文や特定の View の文書群が対象になるので Java Agent の利用が最適です)後の、実際の分類処理の呼び出しは文書の保存時に行われています。DB を確認したところ、Postsave の処理の中で、文書 ID と分類対象の文章を環境変数にセットし、Java Agent を呼び出していました。Java Agent は環境変数から分類対象の文章を取得し、NLC での分類を実行、その結果を 文書 ID を元に取得した文書に書き込むという処理になっていました。

### Notes Client Java UI API ならできそうですが...
Notes 8 からスタンダード版 は Eclipse の上で動いています。Notes 内の Eclipse プラグインで Notes Client Java UI API を利用することで、編集中の文書を含む各種の UI にアクセスできます。
[Notes Client Java UI API 概要](https://www.ibm.com/developerworks/jp/ysl/library/lotus/y-lot-javauiapi/index.html) という記事があり、編集中の文書のフィールド値の取得や変更も記載されています。
ただ、ちょっと敷居が高そうなので、他の方法を考えてみました。

### LS2J で LotusScript から呼び出します。
「Notes Java 連携」などで検索していたら [Notes サポートのつぶやき](http://hnagasim.blog8.fc2.com/) の [LS2J　： LotusScript でJavaのクラスを呼び出してみる](http://hnagasim.blog8.fc2.com/blog-entry-18.html) を見つけました。
LotusScript から、直接 Java のメソッドが呼べるようです。これなら、編集中の文書のフィールドへのアクセスは、LotusScript に任せ、Watson 呼び出しだけ Java で行うことができそうです。

## classpath を通します。
今回は「C:\watson」にファイルを置きました。
notes.ini に下記を追加して、Notes が、今回のクラスを見つけられるようにします。

```
JavaUserClasses=C:\watson\java-sdk-4.0.0-jar-with-dependencies.jar;C:\watson;
```

## フォームにパーツを配置します。

日本語用の「input」、翻訳結果の英文用の「output」の二つのテキストフィールドと、翻訳の実行を行うボタンを配置します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/184930/488a88d2-94e6-9cfb-f919-99efd6163129.png)

## ボタンにコードを書きます。
[LS2J　： LotusScript でJavaのクラスを呼び出してみる](http://hnagasim.blog8.fc2.com/blog-entry-18.html) を参考にコードを書きます。

```
Uselsx "*javacon"

Sub Click(Source As Button)
	Dim ws As New NotesUIWorkspace
	Dim uidoc As NotesUIDocument
	Dim InputStr As String
	Dim OutputStr As String
	
	Set uidoc = ws.CurrentDocument
	InputStr = uidoc.FieldGetText( "input" )
	OutputStr = WatsonTran(InputStr)		
	Call uidoc.FieldSetText("output", OutputStr   )
End Sub

Function WatsonTran( InputStr As String) As String	
	Dim j As JavaSession
	Dim c As JavaClass
	Dim e As JavaError
	Set j = New JavaSession
	Set c = j.GetClass("WatsonTran")
	WatsonTran = c.doIt(InputStr)
End Function
```

## Notes は 9.0.1 + FP8 以降 にしてください。
watson-developer-cloud/java-sdk は Java 7 でコンパイルされていました。
9.0.1 に FP8 を適用すると、Notes の Java 環境が Java 6 から Java 8 になります。FP9 が現在の最新のようです。

[IBM Notes/Domino 9.0.1 の Feature Pack / Fix Pack のダウンロードについて](http://www-01.ibm.com/support/docview.wss?uid=swg21671550)