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

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

2015/03

IBM Bluemix をはじめ、多くの便利な REST API が公開されています。REST API は HTTP プロトコルベースなので、特定のプラットフォームやプログラミング言語環境に縛られることなく、HTTP クライアント機能を持っている多くのプラットフォームやプログラミング言語から利用できるようになっています。

その一方で、IBM ノーツを使っている技術者の立場として、こういった外部の REST API をノーツからどうやって使うか、という情報があまり公開されておらず、「ノーツからは使えないんじゃないか?」と思われてしまっているように感じています。実際、ハードル高いと思う。

1点補足すると、これは「ドミノサーバー」からの話ではなく「ノーツクライアント」からの話です。ドミノサーバーであれば、Java サーブレットも使えるし、もちろんそのサーブレットからノーツデータベースにアクセスすることもできるので、連携もあまり問題ないと思うのですが、問題は「ノーツクライアント上」から「外部の」 REST API を使う、というケースです。 特に「外部の」という部分がミソで、JavaScript の AJAX などから使おうとしてもクロスサイトスクリプティング制約があったりするので、結構難しい問題だと思っています。


で、今回紹介するのは、ノーツクライアントから外部の REST API を使う方法です。"REST API" といっても、要は
 ・特定の URL に対して GET や POST でデータを送信してリクエストすると、
 ・結果が XML や JSON で返ってくるもの
という緩い定義で考えるものにします。これをノーツクライアントから実行して結果を受け取る、というものです。

今回は REST API のサンプルとして、マンホールマップの公開 API を使います。具体的には以下の URL に(GET で)アクセスすると、マンホールマップサービスに投稿されたデータから、最新20件のデータを取り出して JSON フォーマットで返す、というごく一般的(?)なものです:
http://manholemap.juge.me/searchcreated?limit=20&format=json

試しにウェブブラウザでこの URL にアクセスすると、取得結果の JSON がそのまま表示されて、こんな感じの結果になります。ちなみにこの JSON の中身の意味は・・・興味ある人はコメントなどで連絡ください、個人的に教えます(苦笑):
2015033001


この REST API にノーツクライアントからアクセスして JSON データを取得し、中身を解析してノーツで活用しよう、というのが今回の目的です。

まず最初に、これを実現するには「REST API を実行して、結果を取得する」という、ウェブ API ではごく当たり前のことを行う必要があるのですが、ノーツクライアントからこれを実行するには Java エージェントを使う必要があります。LotusScript や式関数などのマクロではノーツに関するカスタマイズ処理を記述することはできますが、TCP/IP 通信や HTTP プロトコルのレベルで処理をカスタマイズする方法は用意されていません。LSX(LotusScript eXtension) や WinSock の DLL を使って TCP/IP のソケット通信を行って・・・という手段がないわけではないと思いますが、そこまで自前で用意した上で更に HTTP プロトコルを実装、となるとさすがに非現実的です。その点、Java を使えば TCP/IP 通信は標準で持っているし、外部の便利なライブラリを使って比較的簡単に HTTP 通信を実現することもできます(更に言うと今回の例では JSON の解析も行う必要がありますが、それもライブラリに任せることができます)。 という背景もあって、今回は Java エージェントを使って REST API を実行します。

実際に Java エージェントを作る前の準備として、HTTP 通信用の Java ライブラリを用意しておきます。選択肢としてはいくつかあると思いますが、サンプルの多さなどから自分が個人的に使っているのが Jakarta Commons(Apache Commons)HTTP Client 3.1 です。この本体と、更に依存関係で必要な Logging ライブラリ、そして Codec ライブラリを全てダウンロードします。 更に実行結果の JSON テキストを取得した後の解析用に JSON ライブラリが必要になるので、これも JSON simple ライブラリをダウンロードしておきます。これらは同様の機能を持っているものであれば別のライブラリを使ってもいいのですが、以下のサンプルではこれらを使っている前提で紹介します。

以上をまとめて、以下の表のダウンロードサイトからライブラリ(のバイナリ)をダウンロードして、ダウンロードしたモジュールを展開するなどして表内右端列の4つの JAR ファイルをあらかじめ取得しておいてください。図のように同じフォルダに格納しておくと後で便利です(いずれも 2015年3月30日時点の最新バージョンです):
2015033002

ライブラリダウンロードサイト必要なファイル
HTTP Client 3.xCommons HttpClient Archivescommons-httpclient-3.1.jar
LoggingDownload Apache Commons Loggingcommons-logging-1.2.jar
CodecDownload Apache Commons Codeccommons-codec-1.10.jar
JSON simpleDownloads - JSON simplejson-simple-1.1.1.jar


では改めてノーツ上で Java エージェントを作ります。目的のデータベース(なければ新規に作って)をドミノデザイナーで開き、コード - エージェントをダブルクリックして選択後に「新規エージェント」ボタンをクリックして、エージェントを追加します:
2015033000


新規エージェント作成画面でエージェント名(図では "REST API Sample")を入力し、エージェントタイプに "Java" を選択して OK ボタンをクリックし、Java エージェントを作成します:
2015033003


新規に Java エージェントが追加されました。この中身を記述する前に、先ほど用意した4つのライブラリファイルを、このエージェント内にインポートして使えるようにしておきます。エージェント画面内の インポート - アーカイブ を選択します:
2015033004


ソースディレクトリに JAR ファイルが格納されているフォルダを指定し、インポートしたい JAR ファイルをまとめて指定して「終了」ボタンをクリックします。JAR ファイルが別々のフォルダに格納されている場合は、この手順を繰り返して全ての JAR ファイルをインポートします:
2015033005


Java エージェントのアーカイブに指定した JAR ファイルが追加されていることを確認してください。これで Java エージェント内でこれらのライブラリを使った処理を記述することができるようになりました。改めて javaAgent.java をダブルクリックして、エージェント処理の実装にとりかかります:
2015033006


ドミノデザイナー内でコードエディタが開き、javaAgent.java の編集状態になります。ここで記述された内容がこのエージェントの実行内容になります。コメントで "(Your code goes here)" と書かれた箇所の後に(というか、その前の部分を触らないように)実行内容を Java で記述します:
2015033007


今回の場合は、目的の REST API を実行して、その結果を取得する、という実装を行います。取得結果を最終的にどう扱うか(例えばノーツのデータとして格納するのか?別のデータベースに格納するのか?単に表示するだけか?など)は別に検討する必要があると思いますが、今回は結果を Java コンソールに出力する、という内容にします。なので、実装コードはこんな感じです。ここはもうノーツの世界ではなく、普通に Jakarta HTTP Client を使っているだけです:
  :
  :
  // (Your code goes here)
  HttpClient client = new HttpClient();
  GetMethod get = new GetMethod( "http://manholemap.juge.me/searchcreated?limit=20&format=json" );
  int sc = client.executeMethod( get );
  if( sc == 200 ){
    String json = get.getResponseBodyAsString();
    JSONParser parser = new JSONParser();
    JSONArray objs = ( JSONArray )parser.parse( json );
    int n = objs.size();
    for( int i = 0; i < n; i ++ ){
      JSONObject obj = ( JSONObject )objs.get( i );
      Long id = ( Long )obj.get( "id" );
      String username = ( String )obj.get( "username" );
      String text = ( String )obj.get( "text" );

      //. とりあえず整形してコンソールに出力
      String line = i + ": [" + id  + "] " + text + "(" + username + ")";
      System.out.println( line );
    }
  }
  :
  :

これで javaAgent.java およびこの(今回の例だと "REST API Sample")エージェントを保存します。


では試しにこのエージェントをノーツクライアント上で実行してみます。ノーツでこのエージェントを作ったデータベースを開きます。今回の例では最終結果を Java コンソールに出力しているので、その確認のためメニューから ツール - Java デバッグコンソールの表示 を選択します:
2015033001


こんな感じの Java コンソールウィンドウが開きます。実行結果はこの中に表示されるので、ウィンドウを閉じずにこのまま続けます:
2015033002


改めてノーツクライアントの画面に戻り、メニューから アクション - (作ったエージェント名(今回の例だと "REST API Sample")) を選択して、上記で作成した Java エージェントを実行します。実行方法はこれ以外にトリガを用意しても構いませんが、動作確認目的であれば、この方法が簡単でオススメです:
2015033003


作成した Java コードが正しく実行されると、REST API が呼び出され、結果の JSON テキストがパース&解析されて、取得したデータが1行ずつ Java コンソールに表示されるはずです:
2015033004


この例だと取得結果を Java コンソールに表示するだけでしたが、この結果を DB に格納するなり、これを元に HTML を作ってブラウザで表示する(参考記事)なり、色々な応用があると思います。ともあれノーツクライアントからであっても一般的な REST API を実行することができました。

後はこれを IBM Bluemix 上の各種 Watson API など、様々な外部 REST API を使う形で応用できると思っています。ノーツのデータを元に人工知能 API を使った解析を行うなど、いろんな使い方の可能性が広がると思っています。

 

Java のコードからブラウザを起動できることを知りました。
環境依存とかで面倒そう、、と思っていたのですが、AWT の Desktop クラスを使うことで比較的簡単に実現できちゃいました:
import java.awt.Desktop;
import java.net.URI;

  :
  :

String uriString = "http://manholemap.juge.me/"; // 開くURL
Desktop desktop = Desktop.getDesktop();
try{
  URI uri = new URI( uriString );
  desktop.browse( uri );
}catch( Exception e ){
  e.printStackTrace();
}

  :
  :

これだけで指定した URL のページ(この例だとマンホールマップ)がデフォルトブラウザで開きます。

これがどんな時に便利かというと、一般的な Web アプリケーションの中で(サーブレットや JSP で)Java を使う時は HttpServletRequest/HttpServletResponse クラスなどから UI 部分との連携ができるのですが、スタンドアロン Java プログラムや、IBM Notes などのスタンドアロンアプリケーションから Java を使おうとすると、コードは実行できても UI 部分との連携がしにくくて、「実行結果をどうやって見せるか」の問題があるのでした。Java コンソールに出力するくらいはできても、それを見てもらうのも至難の技だし、そもそも見栄えも悪い。

その点、ブラウザを起動できてしまえば、パラメータに実行結果を含めちゃったりすることで実行結果を渡す方法もあるし、見栄えも HTML/CSS で自由度高く作れるしで、重宝します。

なお、java.awt.Desktop クラスはこれ以外でもファイルを関連付けられたアプリで開く open メソッドや、印刷する print メソッドなど、デスクトップ関連の便利なメソッドが用意されています。ノーツ系の皆さんは覚えておくと便利かも(とっくに知ってたらごめんなさい):
Desktop(Java Platform 7)






 

CentOS などの Linux/UNIX 環境で top コマンドを使ってプロセスの様子を確認することは珍しくないと思いますが、その機能拡張版である htop コマンドを使ってみました。普通の(?)top コマンドではわからない情報も表示してくれて便利です。Mac 環境でも使えます。


RedHat/CentOS 系 OS であれば、導入は yum コマンドで一発ですが、EPEL リポジトリを有効にする必要があります。未導入の場合は最初に EPEL を導入しておきます。以下は CentOS 6 の場合のコマンド例です:
# rpm -ivh http://ftp-srv2.kddilabs.jp/Linux/distributions/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm (64bit 環境の場合)
# rpm -ivh http://ftp-srv2.kddilabs.jp/Linux/distributions/fedora/epel/6/i386/epel-release-6-8.noarch.rpm (32bit 環境の場合)

リポジトリの導入ができていれば、次のコマンドで htop のインストールもできます:
# yum install htop

シェルから "htop" で実行します:
# htop

こんな感じで起動します。テキストモードですが、画面は色分けされ、top と比べて見やすく表示されています。画面上部に CPU やメモリの様子がテキストグラフィックで表示されていて、これはこれでわかりやすくなっています:
2015032701



実はこの画面内ではカーソルキーが有効になっていて、カーソルキーの上下で特定のプロセスに移動し、F7/F8 でプロセスの優先度を変えたり、F9 で Kill したり、、といった操作もできます:
2015032702

 

F1 キーを押すとショートカットキーコマンドの一覧が表示されます:
2015032703


F5(t) でツリービューにして、+/- で展開/格納したり、といった表示も可能になるようです。試してみるとこんな感じ。カーソルがある行の情報だけが格納されています:
2015032704


F3 キーでプロセスの検索もできます。この図では "/sbin/rsys" まで検索して、カーソル行が rsyslogd のプロセスに移動している様子です:
2015032705


特定のユーザーのプロセスだけを表示する、といった操作も可能です。まず u キーを押して、ユーザーの一覧から目的のユーザーを選んで Enter 、です:
2015032706


インストールも簡単だし、シェル環境では入れておいて損のない、便利なツールだと思ってます。


 

IBM のクラウドサービスの1つに IoT(Internet of Things) Foundations があります:
IBM Internet of Things Foundation
2015031701


このポータルサイトでは、各種 IoT デバイスの情報やクイックスタート情報などが提供されるほかに、インターネットから使えるシミュレータが提供されています:
IoT Sensor
2015031702


この仮想 IoT シミュレータには温度/湿度/機器温度という3つの仮想センサーが付いています。横スワイプでセンサーの種類を切り替えることができて、画面内のボタンでそれぞれの数値を切り替えることができるようになっています。また画面右上にはこの IoT 機器が使っている仮想的な MAC アドレスが表示されているはずです:
2015031703


右上の MAC アドレス部分をクリックすると、この各センサーの値を2秒毎に更新して表示する確認画面が表示できます。この図では Object Temprature(機器温度)を 25 度から 31 度に上げた直後の様子が示されています:
2015031704


この画面下の表をクリックすることで、別のセンサーのグラフに切り替えることができるようになっています:
2015031705


IoT (のシミュレータ)がスタンドアロンで動いている、この部分だけを見ると特別に面白いことはないですよね。

でもこのグラフが表示される確認画面は MAC アドレスだけを頼りに動いています。その IoT 機器が物理的に存在するものなのか、仮想的なシミュレータなのかは区別していません。例えばラズベリーパイなどの IoT 機器に温度センサーが付属していて、インターネットにつながった状態で稼働しているのであれば、そのラズベリーパイの MAC アドレスを指定することで、この確認画面にはラズベリーパイの温度センサーからの情報が表示される、ということです。


ということは、各種温度情報を MAC アドレスベースのセンサーから提供するような IoT 実機の代わりにこのシミュレーターを使ってアプリやサービスを開発することができて、本番の IoT 実機を使う時は MAC アドレスを実機のものに切り替えればよい、ということになります。要は単にスタンドアロンでこのシミュレータが動いているわけではなく、非常に手軽にリモート IoT 機器のシミュレーションを行うことができる環境が提供されていることになるのでした。


このブログエントリでは、このインターネット上で手軽に使える IoT Sensor シミュレータの紹介までとしますが、この続きとして、このシミュレータを使った IoT アプリケーションを開発するサンプルを紹介する予定です。お楽しみに。




 

ウェブサービスを開発・公開する上で、URL のリライトの問題があります。

例えば、アプリケーションとしては
 http://xxx.myserver.com/abc.php?country=Japan&pref=Chiba&city=Funabashi
というパラメータを受け取って処理するようなページやサービスがあったとします。

単に動かすだけなら、このパラメータ処理でいいのですが、SEO 対策や、単に長くて見難いという理由から、これを
 http://xxx.myserver.com/abc.php/Japan/Chiba/Funabashi
のような URL パターンで受け取りたいことが出てきます。

この例であれば、
 http://xxx.myserver.com/abc.php/AAA/BBB/CCC
という URL パターンを有効な URL として認識し、実際に処理する際には
 http://xxx.myserver.com/abc.php?country=AAA&pref=BBB&city=CCC
と内部的に書き直し(ReWrite)してから処理をする、ということになります。これが URL リライトです。

HTTP サーバーに Apache HTTPD を使っている場合は、この URL リライト機能が標準モジュールになっていて、mod_rewrite モジュールを有効にして、httpd.conf や .htaccess に変換ルールを記述するだけで URL リライトが実現できます。 ではウェブサーバーに Apache Tomcat など Apache HTTPD を経由しない Java アプリケーションサーバーを使っている場合のリライト処理はどうすればいいでしょう??


その答の1つが UrlRewriteFilter です。jar ファイル1つをプロジェクトに組み込み、専用の XML ファイルに変換ルールを記述することで、Java アプリケーションサーバーでも mod_rewrite のようなリライト処理を実現できるようになります:
urlrewritefilter00


実際に使ってみたサンプルを紹介します。まずは公式ページから urlrewritefilter-4.0.3.jar ファイルと、サンプルの urlrewrite.xml ファイルをダウンロードして保存します。
urlrewritefilter01


Java アプリケーションのプロジェクト内にこれらのファイルを配置します。まず urlrewritefilter-4.0.3.jar は WEB-INF/lib/ に、urlrewrite.xml は WEB-INF にそれぞれ保存します。次に web.xml を編集します:
urlrewritefilter02

WEB-INF/web.xml の </web-app> の直前に次の内容を追加して、このウェブアプリケーション内の全ての URL パターン(/*)に UrlRewriteFilter フィルターを適用することを宣言します:
  :
  :
<filter>
  <filter-name>UrlRewriteFilter</filter-name>
  <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>UrlRewriteFilter</filter-name>
  <url-pattern>/*</url-pattern>
  <dispatcher>REQUEST</dispatcher>
  <dispatcher>FORWARD</dispatcher>
</filter-mapping>

</webapp>

実際の変換パターンは WEB-INF/urlrewrite.xml ファイルの <urlrewrite> 要素内に記述します。以下の例では2つの変換パターンを記載しています:
<urlrewrite>
  :
  :
  <rule>
    <from>/urlrewrite/(.*)/(.*)/(.*)</from>
    <to>/urlrewrite?x=$1&y=$2&z=$3</to>
  </rule>
  <rule>
    <from>/urlrewrite/(.*)/(.*)</from>
    <to>/urlrewrite?a=$1&b=$2</to>
  </rule>
</urlrewrite>

前者では /urlrewrite/ 以下に / をセパレータとして3つのパラメータを受け取る、つまり
 /urlrewrite/XXX/YYY/ZZZ 
のような URL 指定があった場合に、内部的に
 /urlrewrite?x=XXX&y=YYY&z=ZZZ
のようにリライトして処理する、という変換パターンを記載しています。

後者では同様に2つのパラメータを受け取った時、つまり
 /urlrewrite/AAA/BBB
のような URL 指定があった場合に、内部的に 
 /urlrewrite?a=AAA&b=BBB
のようにリライトして処理する、という変換パターンを記載しています。

#上記例ではパラメータが2つの時と3つの時とで、異なるパラメータ変数に渡すようにしています。
 もちろんこの部分は定義次第です。


後はこれらのパラメータ(リライト後のパラメータ)に対応して処理するような /urlrewrite を(サーブレットなどで)実装すればよい、ということになりますね。




 

このページのトップヘ