まだプログラマーですが何か?

プログラマーネタとアスリートネタ中心。たまに作成したウェブサービス関連の話も http://twitter.com/dotnsf

タグ:notes

久しぶりの LotusScript ネタです。LotusScript は IBM ノーツ/ドミノのカスタマイズに使えるマクロ言語です。内容そのものはノーツじゃなくても(VBA でエクセルなどにも)応用できると思いますが、Windows 前提です。

Windows OS に標準搭載されている ServerXMLHTTP オブジェクトをノーツの LotusScript から使って、LotusScript で WEB API っぽいことを実現してみました。

まず ServerXMLHTTP オブジェクトについて。MSDN によるとこんなものです:
https://msdn.microsoft.com/ja-jp/library/ms762278(v=vs.85).aspx

簡単に言えば「HTTP クライアントライブラリとして使える ActiveX オブジェクト」です。このオブジェクトをインスタンス化すれば、比較的簡単に HTTP クライアントプログラムが作れます。特にノーツのマクロ言語である LotusScript はソケット通信とかネットワークプログラミングに若干弱いところがあるので、このオブジェクトを外部利用して WEB API を使ってみよう、という試みです。

例えばこんな感じ。開発環境であるドミノデザイナーを使ってノーツデータベースのエージェントを LotusScript で作り、Initialize サブルーチンに以下のような内容を記載します(エージェント名は ServerXMLHTTP としました):
Sub Initialize
  Dim obj As Variant

  Set obj = CreateObject( "Msxml2.ServerXMLHTTP.6.0" )
  Call obj.open( "GET", "http://ibm.com/", False )
  Call obj.send()
  MsgBox obj.responseText
End Sub

内容がシンプルなのでなんとなく理解できると思いますが、簡単に解説すると CreateObject を使って ServerXMLHTTP オブジェクトインタンスを生成し、"http://ibm.com/" を HTTP GET して、その内容をメッセージボックスで表示する、というものです。要するに http://ibm.com/ の HTML ソースコードを画面に表示する、というものです。

またエージェントのプロパティとして、実行時のトリガーは「イベント」で「アクションメニューの選択」、対象は「データベースの全ての文書」に設定しておきます。もちろん実行内容によってはここを変更する必要がでてきますが、今回の例ではこの設定でメニューから選択して実行できるようにしました:
2017081001


改めてこのデータベースをノーツで開くと、メニューから作成したエージェント(図では "ServerXMLHTTP")が選択できるようになっているはずです。これを選択して実行すると・・・
2017081002


こんな感じのダイアログボックスが表示され、中に http://ibm.com/ の HTML ソースコードが表示されているはずです:
2017081003


いかがでしょう。上記例では HTTP GET の例を紹介しましたが、この ServerXMLHTTP オブジェクトを使うと、POST など他のメソッドを指定することもできるし、もちろん送信データを指定することもできます。その辺りの詳しい話は公式ドキュメントを参照ください:
https://msdn.microsoft.com/ja-jp/library/ms762278(v=vs.85).aspx


HTTP クライアントがここまで簡単に使えると、各種 Web API が使えるようになるので、IBM Bluemix のワトソン API をノーツクライアントから(それもフロントエンドから)直接実行する、なんてことも可能になると思っています(余談ですが以前に Java を使って、ノーツのバックエンドからワトソン API を使う、という内容を紹介したことがあります。その記事はこちら)。


ノーツデータを広く応用・活用する際に使えそうなライブラリです。

IBM Notes 9.0.1 の FP(Feature Pack) 8 がリリースされました。有効なサポート契約をお持ちであれば、以下の FixCentral サイトからダウンロードして適用いただくことが可能です:
http://www-01.ibm.com/support/docview.wss?uid=swg24037141


適用後にメニューから ヘルプ - IBM Notes について を実行すると、リリースバージョンが変更できていることが確認できます。自分の環境にも早速適用してみました:
2017030901


実は以前にこのブログの中で、「ノーツでワトソン」というエントリを紹介したことがありました(比較的アクセス数の多い、人気エントリの1つです):
http://dotnsf.blog.jp/archives/1062359514.html

↑この中でも触れているのですが、Watson API のセキュリティ仕様変更があり、JDK 1.8 未満の環境から Watson の REST API へ https リクエストを実行するとエラーが返されるようになってしまっていました(ノーツは JDK 1.6 を使っていたのでエラーが発生していました。上記エントリはその回避方法も含めて紹介しているものです)。

が、今回の 9.0.1 FP8 では、内蔵 JDK バージョンが 1.8 に変更される、という大きな変更が含まれていることになっています。これによって Watson API のセキュリティ要件を満たすことになるので上記エントリのような回避策も不要になることが期待できます。

というわけで、IBM Notes 9.0.1 FP8 の実際の JDK バージョンを確かめるためのプログラムを作って実行してみることにします。まずは Domino Designer で適当なデータベースアプリケーションを作り、その中に Java のエージェントを新規に作成します(エージェントの名称は FP8 としました):
2017030902


Java エージェントの中身を記述します:
2017030903


具体的には以下のようなコードを記述しています(初期状態の内容と比較して、青字部分を追記しています):
import java.util.Properties;

import lotus.domino.AgentBase;
import lotus.domino.AgentContext;
import lotus.domino.Session;

public class JavaAgent extends AgentBase {
  public void NotesMain() {

    try {
      Session session = getSession();
      AgentContext agentContext = session.getAgentContext();

      // (Your code goes here)
      Properties props = System.getProperties();
      props.list(System.out);
    } catch(Exception e) {
      e.printStackTrace();
    }
  }
}

↑システム内の全プロパティを取得して、標準出力(System.out)にプロパティ名とその値を表示する、という内容です。Java のバージョンもプロパティの1つなので、この出力結果の中に含まれているはずです。

このエージェントをメニューから実行できるよう、基本プロパティのトリガーはイベントで「アクションメニューの選択」、対象は「データベースの全ての文書」とした上で、このエージェントを保存します:
2017030904


では作成したエージェントを実行してみます。結果は標準出力に出されるので、あらかじめメニューのツールから、Java デバッグコンソールの表示 を選択して、出力画面を表示しておきます:
2017030905


改めてメニューから アクション - FP8 を実行します:
2017030906


するとエージェントの実行結果が Java デバッグコンソールに追加記載される様子が確認できます:
2017030907


画面を少しずつ下にスクロールしていくと、"java.version" というプロパティの値が "1.8.0" になっていることが確認できました。ちゃんと(?) 1.8 が使われているようです:
2017030908


 というわけで、IBM Notes 9.0.1 FP8 からは JRE/JDK 1.8 が使えるようになりました。これで Java プログラミング時に互換性を心配しながらコーディングする必要はなくなりました。


IBM LinuxONE(メインフレーム版 Linux)に IBM Domino をインストールすることに挑戦してみました:2017012200


いくつか前提を紹介します。まず LinuxONE の環境は IBM LinuxONE コミュニティクラウド上の RHEL 6.x のサーバーインスタンスを使うことにします(最大 120 日間無料で使えます)。また IBM Domino を導入する際にはその環境に X Window のデスクトップ GUI が必要です。これらの環境を用意するまでの手順はこちらを参照ください:
IBM LinuxONE コミュニティクラウド上で X Window のデスクトップ環境を構築する


次に IBM Domino ですが、これは無料で入手できるものではありません。IBM Domino のサブスクリプション契約をお持ちで、インストールモジュールをダウンロードする権利をお持ちの人のみが入手可能なものです。

(訂正)
IBM Domino は IBM 無料トライアルダウンロードプログラムに含まれており、IBM LinuxONE 向けのエディションもこの対象でした:
https://www.ibm.com/developerworks/downloads/ls/lsds/

2017012302


IBM ID をお持ちか作成いただくことで、こちらからトライアル版をダウンロードしてご利用いただくことも可能です:
2017012301



(有効なサブスクリプション契約をお持ちの場合は、)"Linux for z System" 向けの IBM Domino の最新版をダウンロードしてください。ちなみに 2017/Jan/22 時点では V9.0 英語版がパーツ番号 CIBM5EN で検索することで見つけることができるはずです。ファイル名は DOMINO_9.0_64BIT_LIN_ZS_EN.tar でした。このファイルを入手済みであるとして、以下を紹介します。

LinuxONE に限らないのですが、Linux 版の IBM Domino は導入前に root ではない実行時のユーザーおよびそのグループを OS 内に作成しておく必要があります。以下、notes グループの notes ユーザーによって実行する前提として、これらのグループとユーザーを作成しておきます:
# groupadd notes
# useradd notes -g notes

ユーザーを作成したら、ダウンロードしたインストールモジュールファイルを展開し、zlinux64/domino フォルダ内のインストーラー(install)をコマンドラインから実行してインストール作業を行います:
# cd /data
# ls
DOMINO_9.0_64BIT_LIN_ZS_EN.tar

# tar xvf DOMINO_9.0_64BIT_LIN_ZS_EN.tar

# cd zlinux64/domino

# ./install

インストーラーを実行すると、次のようなインストール画面に切り替わります。ここから次へは TAB、変更時はスペース+変更内容+Enter で、必要に応じてオプションを編集しながらインストーラーの作業を進めます:

2017012002


LinuxONE で利用する場合、唯一意識すべきはインストール先のディスクだと思われます。比較的メインディスクに空きがない状態で導入するには /data 以下を指定して導入するようにします。以下の例はデータディレクトリをデフォルトの /local/notesdata から /data/local/notesdata に変更している様子です:
2017012003


最終確認画面が表示されています。問題なければ TAB キーでインストールが開始されます:
2017012004


インストールが完了しても、IBM Domino の場合はセットアップを行わないと動きません。というわけでセットアップに移りますが、その前に1つ作業があります。 xhost の設定をしておかないとセットアップ時に利用する GUI のウィンドウが開かないのです。

またここからは X Window システムのデスクトップ GUI 環境が必要になります。というわけでまずは VNC クライアントを使ってこのサーバーのデスクトップを開いてターミナルを起動し、この xhost コマンドで notes ユーザーの画面でインストーラーウィンドウが開くようにしておきます:
# xhost +local:notes

そのまま続けて notes ユーザーに su し( root ユーザーでは server は起動しません)、ノーツデータディレクトリがカレントディレクトリになっている状態から server を実行します。これ実はサーバーの起動手順と同じですが、最初の一回はセットアップモードでの起動が行われます:
# su - notes

$ cd /data/local/notesdata
$ /opt/ibm/domino/bin/server

すると GUI に Domino セットアップのフラッシュスクリーンが表示され・・・
2017012005


しばらくすると、見慣れた Domino サーバーセットアップの画面に遷移します。ここからはいつもの(Windows とかの)セットアップと同じです:
2017012006


セットアップが完了し、再度 server コマンドを実行すると、今度は Domino サーバーがコンソール内で起動し、Domino サーバーとして利用可能になります:
zdomino


IBM Domino は有料のソフトウェア製品であり、この製品(特に IBM z Systems 版)を無料で入手する方法は限られてしまいますが、その手段をお持ちの方であればのインストールモジュールを入手する方法がちと面倒ではありますが、IBM Domino はメインフレーム上のパブリッククラウド Linux に導入して使うまでの環境は(IBM LinuxONE コミュニティクラウドを使うことで)無料で用意できることになります。

試験的な利用も含め、パブリッククラウド上で IBM Domino の環境を作って動かしてみたい、という方は是非一度お試しください。

先日のブログで、IBM Domino のログを外部の Web API 経由で取得する、という方法を紹介しました:
ノーツの Web エージェントで外部からログを取得する

要は log.nsf には手を付けずに、log.nsf の中身を取得して XML 出力するような API を外部データベースに Web エージェントとして作成して呼び出す、 という内容でした:
2016120302


今回はその応用編です。API でログが取得できるようになったので、その取得したログの(テキストの)内容を更に分析してみます。

今回新たに使う API は Watson Tone Analyzer です:
2016120500


Tone Analyzer は IBM Watson が提供するコグニティブ API の1つで、会話の中で発生する喜び、悲しみ、怒りといった「トーン」をテキストの内容から検出する API です。現在は大きな分類として「感情(怒り:Anger、嫌悪:Disgust、不安:Fear、喜び:Joy、悲しみ:Sadness)」、「社交性(開放性:Openness、誠実性:Conscientiousness、外向性:Extraversion、協調性:Agreeableness、情緒不安定性:Emotional Range)、「文体(分析的:Analytical、確信的:Confident、あいまい:Tentative)」という3種類のトーンを分析します:
2016120501


なお 2016/Dec/05 時点では、この API は日本語テキストには未対応です。なので、日本語の会話テキストをそのまま API のインプットデータに使うことは現時点ではできません。今の段階では使い方も限られてしまいますが、英語テキストを使えばどんな API なのかを確認する程度のことはできると思います。


この API は与えられたテキストをもとに、上記3種類のトーン毎に各要素の割合を識別して結果を 0 から 1 までの数値で返してくれます。結果の判断の方法は一概に言えないのですが、一般的には 0.75 以上であればその要素が表面化していて、0.5 以上の場合は表面化せずにも含まれている(それ以下は要素として見られない)と判断するようです。この辺りの数値結果の考え方について詳しくはこちらを参照ください:
Understand your tone score


というわけで、IBM Domino の log.nsf から取り出したログの英語テキストを、この Tone Analyzer API を使って「IBM Domino はどんな感情のログを吐いているか?」を調べてみることにします。ちなみに PHP 版のソースコードはこちらに公開しておきます:
https://github.com/dotnsf/ToneAnalyzerWithDominoLog

上記リポジトリの内容をダウンロード&展開するかクローンして、credentials.php ファイルの内容を自分の環境(Domino ログを取得する歳の URL と、Tone Analyzer の username 及び password)に合わせて編集します。そして index.php をブラウザから呼びだすと、こんな感じの画面が表示されると思います:
2016120502


index.php の内容を見ていただくとわかりますが、まず前回紹介した内容を使って Domino の log.nsf からログを Web エージェント経由で取得します。そしてその取得したテキストログをまとめて Tone Analyzer へ送り、感情分析結果を取得して、表にしている、というものです。jquery-ui を使って、感情スコアのスライダー表示も実装しています。

この表の部分だけを拡大したものがこちらです:
2016120503


この結果から、0.75 を超えているのは感情の5要素にはありません。機械的なログを分析しているので、これはある意味で正しい結果と考えられます。次に文体の3要素の中では Analytical(分析的)が 0.75 を超えているので、分析的なテキストであったといえます(これもログなのである意味正しいと言えます)。そして社交性の5要素のうちでは Conscientiousness(誠実性)と Emotional Range(情緒不安定性) が 0.75 を超えていました。な、なんかメンヘラっぽいけど、うちの Domino サーバーは大丈夫なんだろうか? (^^;


と、まあ Tone Analyzer はこんな感じで使えます。このブログでは IBM Domino のログを対象に解析していますが、もちろん他のミドルウェアサーバーのログや、テキストを元に解析できます。現状は日本語未対応なのでできることも限られてしまいますが、ある意味今のうちにいい勉強ができるともいえます。

なお、Watson Tone Analyzer はサンプルアプリのサイトから実際にテキストを与えて、感情分析結果を確認することも可能です。試してみたいテキストがあればこちらから確認してみてください:
https://tone-analyzer-demo.mybluemix.net/


先日紹介したこのエントリの続きです。今度はノーツデータベースの中身を取得する Web API をエージェントで作成してみます:
ノーツの Web エージェント


対象とするノーツデータベースは「ログ」にします:
2016120301


このログデータベースは Domino サーバー上に log.nsf として存在しています。個々のログ内容は Events フォームのドキュメント内の EventList フィールド内に配列の形で格納されています:
2016120303


というわけで、同データベースからログを取り出して、XML 化して出力する、という Web API(Web エージェント)を作ってみました。基本的な考え方や作り方は前回紹介したものと同様ですが、実際の処理内容だけを変えています:
  :
:
public class JavaAgent extends AgentBase{ public void NotesMain(){ try{ Session session = getSession(); AgentContext agentContext = session.getAgentContext(); // (Your code goes here) String xml = "<?xml version=\"1.0\"?>\n<eventlist>\n"; //. 直近1週間のログのみ対象とする Date dt0 = new Date(); long t = dt0.getTime(); t -= ( 7 * 24 * 60 * 60 * 1000 ); dt0.setTime( t ); //. この(エージェントのある)データベースと同じサーバー上の log.nsf を対象とする Database cdb = session.getCurrentDatabase(); String server = cdb.getServer(); Database logdb = session.getDatabase( server, "log.nsf" ); //. Events フォームの文書を取り出す DocumentCollection docs = logdb.search( "Form=\"Events\"" ); for( int i = 1; i <= docs.getCount(); i ++ ){ Document doc = docs.getNthDocument( i ); //. EventList フィールドの配列値を取り出す Vector eventlist = doc.getItemValue( "EventList" ); Enumeration event = eventlist.elements(); while( event.hasMoreElements() ){ String line = ( String )event.nextElement();      //. 日付とログ文字列に分離 int x = line.indexOf( " " ); if( x > 0 ){ String dt = line.substring( 0, x ); //. YYYY/MM/DD hh:mm:ss String msg = line.substring( x + 3 ); //. 対象日(7日以内)のログかどうかを確認 Date dt1 = new Date( dt ); if( dt1.after( dt0 ) ){ //. XML 用にサニタイズ msg = msg.replaceAll( "\n", "" ); msg = msg.replaceAll( "\r", "" ); msg = msg.replaceAll( "&", "&amp;" ); msg = msg.replaceAll( "<", "&lt;" ); msg = msg.replaceAll( ">", "&gt;" ); msg = msg.replaceAll( "\"", "&quot;" ); xml += ( "<event datetime=\"" + dt + "\">" + msg + "</event>\n" ); } } } } xml += "</eventlist>\n"; //. 画面に出力 PrintWriter pw = getAgentOutput(); pw.println( "Content-Type: text/xml" ); pw.println( "" ); pw.println( xml ); pw.close(); }catch( Exception e ){ e.printStackTrace(); } } }

↑基本的な考え方は前回紹介したものと同じです。出力内容は log.nsf の内容なので、このデータベースを取得して、対象(1週間以内)のログを探して1行ずつ XML を生成し、最後に text/xml として出力する、という内容を Java で記述しています。

※同様の Web エージェントを LotusScript で記述する場合、最後の出力部分は Print 文で代用してください。


このエージェントをブラウザから
  http://(domino サーバー名)/(DB名)/(エージェント名)?OpenAgent
という URL を指定して実行します
2016120302


Domino サーバーのログの内容が Web API で外部から取得できるようになりました。他のデータベースでも同様に応用できると思います。

このページのトップヘ