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

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

タグ:notes

ベータ2が公開されたばかりの IBM Notes(以下「ノーツ」)V10 の、個人的に待望だった新機能「LotusScript で HTTP リクエスト」を早速試してみました。


1989 年(平成元年!)にバージョン1がリリースされたノーツはメールやインターネットの標準機能を取り込みながら進化してきました。特徴の1つでもあるマクロ言語の機能も簡易的な@関数式から VBA 互換の LotusScript 、Java 、そして JavaScript と時代に即して対応範囲を広げてきました。

ただ、ここ数年のカスタマイズの中で不便に感じることも出てきました。それが(この下で紹介する新機能でもある)HTTP リクエスト機能です。各種 REST API などと連携しようとすると HTTP リクエストを実行して、その結果を受け取って・・という一連の処理が必要になります。

ノーツで HTTP リクエストを実行できなかったわけではありません。ノーツは JVM を内蔵しており、Java で(エージェントと呼ばれる)マクロを記述して実行することができます。この方法を使うことで(つまり Java のネットワーク機能を使うことで)HTTP リクエストを実行することはこれまでも可能でした。

一方で制限事項もありました。ノーツの Java エージェントはバックエンド機能として提供されており、そのフロントエンド機能は提供されていませんでした。具体的にいうと「編集中の(未保存の)画面の Subject フィールドの値を取り出して、その値をパラメータとして HTTP リクエストを実行」といった処理をしようとすると、青字部分は Java を使えばいいのですが、赤字の部分の処理は Java からは実行できないのでした。これを実現するために例えば LotusScript のフロントエンド機能を使って赤字部分の処理を実行し、そこで取り出した値を(ファイル渡しなどの)何らかの方法でバックエンドの Java に渡して処理させる、という連携が必要でした。なので、技術的に不可能でなかったのですが、2つの言語記述による処理を連携させる必要があり、ちと面倒だったのでした。

今回リリースされた V10 ベータ2の新機能「LotusScript から HTTP リクエスト」はこの制約を取り除くことができると思っています。具体的にはフロントエンドの LotusScript で編集中の値を取り出して、そのままバックエンドの LotusScript で HTTP リクエストを実行することができるようになる、というものです。全てが LotusScript の1処理で完結することになり、自然に実装することができるようになると期待していました。その機能を使ってみたので以下で紹介します:



まずはノーツ V10 をインストールします、about 画面はこんな感じです:
20180821


で、肝心の HTTP リクエストは・・・どうやって使うんだろ?? (^^; ベータ版だからなのか、全くドキュメントが見つかりません。。。

それっぽいキーワードでぐぐって、唯一なんとか見つけたのがこの PDF ・・・
http://collabsphere.org/ug/collabsphere2018.nsf/0/789F066AA1414139862582A900620D93/$File/CollabSphere2018%20-%20Elementary.pdf

2018082105
 ↑NotesSession から createHttpRequest() して・・・ってこと?

これ、どこまで信用できる情報かわからないし、情報は充分ではないけれど、今はこれを信じて使ってみることにします。まずは超シンプルに僕が IBM Cloud 上に作った「リアルタイム外為情報」 API をそのまま HTTP GET で呼んでみることにします:
2018082105
 ↑HTTP GET されたら、こんな JSON を返すだけの API


上記 PDF の内容に従って、NotesSession のインスタンスから createHTTPRequest() して NotesHTTPRequest のセッションを生成し、URL を指定して HTTP GET 、その結果を MsgBox でそのまま出力、という内容です。なお PDF に記述されていた Use "class.RemoteHTTP" という宣言をするとエラーになってしまうため使っていません:
2018082103

Sub Click(Source As Button)
  Dim session As New NotesSession
  Dim http As NotesHTTPRequest
	
  url = "http://fx.mybluemix.net/"
	
  Set http = session.CreateHTTPRequest()
  response = http.Get( url )
  Msgbox response
End Sub

実行したら・・・  動いた!!
2018082104


ついに LotusScript だけで HTTP GET Request が動いた瞬間です。わーい、結果は HTTP レスポンスヘッダを含むテキストになってるわけね、ふむふむ。。

あ、よく見るとリクエスト先 URL のプロトコルが "https" ではなく、"http" になっていたので、もう一度 "https" にしてやり直し:
2018082101

Sub Click(Source As Button)
  Dim session As New NotesSession
  Dim http As NotesHTTPRequest
	
  url = "https://fx.mybluemix.net/"
	
  Set http = session.CreateHTTPRequest()
  response = http.Get( url )
  Msgbox response
End Sub


・・・したらエラー(苦笑):
2018082102


なんだ、このエラーは (^^; ベータ版だからなのだろうか?それとも回避手順がある?? あと HTTP GET はいいんだけど、HTTP POST がよくわかりません。http.Post( url, content ) らしいんだけど、content をどう書けばいいんだろ??それから認証が必要な場合は・・・


まだ情報不足もあって調べられることに限界がありますが、一方で LotusScript のみで REST API が実行できそうだ、という感触も得ることができました。これでドキュメントが揃ってくればノーツからの Watson API 連携ももっと楽にできるようになるかな。。


とにかく色々突っ込んでブラックホール化していた自宅のストレージ内を調べていたら、2000~2003 年頃に自分が作っていたアプリケーションソースコードを見つけました!
2017103100


その中に、今でもある程度動くものがありました。当時は github とかなかった(よね?)ので普通に自宅内で管理してたのですが、改めて公開することにしました:
https://github.com/dotnsf/dtopo


以下でその使い方を紹介しますが、まず前提条件として IBM Notes の環境が必要です(というか、公開しているのはノーツ用のアプリケーションです)。またアプリケーションは Eclipse 上で実行するつもりで作られているので、Eclipse が導入されている必要があります。これらはあらかじめインストールされているものとして以下を紹介します。


このアプリケーションはノーツ環境を設定するドミノディレクトリ内のメールルーティング情報および複製ルール情報を元に各サーバー間の関係を視覚化するものです。基本的にはこれらの情報が記述されたドミノディレクトリファイル(サーバーの names.nsf)があれば動かすことができます。試しに今回はこのようなサーバー接続文書情報を持ったドミノディレクトリ(dev/names.nsf)が手元にあるものとして、この内容を視覚化するケースを紹介します:
2017103101
(クリックすると拡大します)


まず上記 github の URL からプロジェクトをダウンロード&展開するか、git clone します。そしてそのプロジェクトを Eclipse のプロジェクトとして開きます。またこのプロジェクトの JRE は Notes にインストールされている Java に切り替える必要があります(詳しくはこちら)。加えてこのプロジェクトに外部 JAR ファイルとしてノーツフォルダ内にある Notes.jar および websvc.jar を追加設定する必要があります:
2017103102


次にプロジェクト内の dtopo.ini をテキストエディタで開きます。そして用意したドミノディレクトリファイルのファイルパスを n: で始まる行に指定してください(以下の例ではドミノデータディレクトリ以下の dev\names.nsf ファイルを指定しています)。ic, nic, cic はアイコン画像ファイルを指定しています。特に変更する必要はありません:
2017103103


そして同プロジェクトソース内の me.juge.dtopo.dtopo.java ファイルを右クリックし、"Run As ..." -> "Java Application" を選んで実行します:
2017103104


実行すると2つのウィンドウフレームが起動します。指定したドミノディレクトリファイルから読み取ったメールルーティング情報と複製ルール情報が別々のウィンドウフレームで表示されています:
2017103105
(↑図は複製ルール(フレーム上部のタイトルに注目))


この図の矢印の視点および終点付近はドラッグ&ドロップで位置を初期位置から調整することができます。またウィンドウフレーム自体のサイズも変更することができます。例えば今回の例では以下のようになりました(上:複製ルール、下:メールルーティング):
2017103101


2017103102


ソースコードは・・・さすがに当時の自分のスキル不足もあって決して見やすいとは思えません(苦笑)。ただ GUI アプリなのでマウスイベントに対するハンドリングを各所でしています。肝となるドミノディレクトリから複製/ルーティング情報を取り出すのは dtopo.java の 555 行目あたりからになります。ノスタルジックな意味合いもあって当時の汚いコードを残したままにしているのですが、興味のある方はこの辺りを参考にしてください(そういえば当時はノーツには  Mac クライアントも Linux クライアントもなかったので、これらの環境で動くかどうかは未検証です):
           :
           :
        Session s = Session.newInstance();
        String dbpath;
        String sserv, dserv, reptype, enabled, tasks;
        Vector sservs;
        String sdom, ddom;

        dbpath = nab;
        if( base.length() > 0 ){
          dbpath = base + "\\" + dbpath;
        }
        Database db = s.getDatabase( server, dbpath );
        if( !db.isOpen() ){
        	db.open();
        }

        //. 接続文書を検索する
        DocumentCollection docs = db.search( "Type = \"Connection\"" );
        for( int dcnt = 0; dcnt < docs.getCount(); dcnt ++ ){
            Document doc = docs.getNthDocument( dcnt + 1 );
           :
           :


ノーツデータを扱う Java アプリケーションの開発を考えている人の参考になれば嬉しいです。


ところで、このアプリケーションを作ったのは(ファイルのタイムスタンプによると)2002 年頃で、ギリギリ Java がクライアントアプリケーション開発にも使われていた頃です(標準の awt に加えて、swing や swt といった GUI のライブラリが出はじめていた頃でした。ちなみに今回紹介しているツールは awt で作っています)。アプリケーションだけでなくフレームワークにも時代を感じさせるものがありますが、その頃のノーツ R5 向けに作ったアプリケーションが 15 年以上の時を経て最新のノーツ9(のドミノディレクトリ)でもちゃんと動くという点がノーツらしいし、まさに Java らしい "Write once, Run anywhere!" だと感じました。

そういえばオラクル資本になってから、あまり "Write once, Run anywhere." って耳にしなくなりましたね。。。

 

Java のアプリ開発をしていて、こんな実行時エラーに遭遇することがあります:
java.lang.UnsatisfiedLinkError: C:\IBM\Notes\nlsxbe.dll: Can't load IA 32-bit .dll on a AMD 64-bit platform


最近は Windows といえば 64bit 版が普通になってきました(よね?)。自分の開発環境も 64bit 版 Windows で、Java 開発環境も(JDK も JRE も Eclipse も)64bit 版を使っています。ここまでは珍しくないと思っています。

しかし開発するアプリケーションによっては外部ライブラリ(JAR ファイル)を指定する必要があり、その JAR ファイルが 32bit のネイティブライブラリを使っていたりするなど、64bit の JDK で 32bit 前提のコードを実行しなければならなくなった場合に上記のようなエラーが発生するのでした。

典型例としては、IBM Notes の Java API を使ったアプリケーション開発が挙げられます。2017/Oct/01 現在、Windows 版の IBM Notes は 32bit 版しか存在していません。Java で IBM Notes の API を実行するには IBM Notes 同梱の Notes.jar 他をインポートして使う必要がありますが、この Notes.jar は 32bit の DLL を参照するため、64bit Java から実行すると上記のエラーが発生します。


エラーの原因が分かったところで、どのように回避すればいいでしょうか? これも解決策としてはシンプルで 32bit Java(JRE) から実行すればよいことになります。32bit JRE をダウンロードして実行してもいいですが、上記のような IBM Notes の JAR を使った場合であれば、IBM Notes が使っている Java をそのまま指定して実行すればよいことになります。

ちとややこしいのが Eclipse のような IDE を使っている場合の指定方法です。まず Java - Installed JREs の中に Standard VM として Notes Java を追加しておく必要があります。Notes Java は(ノーツをインストールしたディレクトリ)/jvm にあるので、このディレクトリを指定して追加します:
2017100101


そして Eclipse の Java プロジェクトの中で JRE System Library として、上記で設定した Notes Java を指定します。これでこのプロジェクト内で作成したアプリを実行する際には Notes Java 内の java.exe が利用されるようになるので、上記のエラーが回避できるようになります:
2017100102



 

久しぶりの 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 プログラミング時に互換性を心配しながらコーディングする必要はなくなりました。


このページのトップヘ