当ブログに掲載しているサンプルは、すべて利用者の自己責任という形でお願いします。
ただし、明らかな不具合がある場合、ご連絡いただければ、訂正記事を出します。
また、こちらのサンプルは、別のサイト等への公開、転載は一切禁止しています。
どうしてもと言う場合は、筆者にあらかじめご連絡ください。

テクてく Lotus 技術者 Slack に参加しよう!

2016年9月26日月曜日

XPagesでカテゴリフィールドに設定する

皆さん、こんにちは。今週で9月も終わりです。9月といえば、一つの区切りという感じがします。
企業の期だったり、テレビでいえば番組改編期だったり。

10月になると何か変わるのかな?って調べてみたら、「厚生年金保険・健康保険の加入対象が広がる」そうです。
私には直接は関係ないのですが、こういうことも知っておかないといけないですね。


閑話休題。


さて、今日もXPagesの話題です。

クラシックアプリでよくやっていた?のが、ダイアログフィールドを作成して、既存のフィールドから選択したり新規に値を設定したりするという、分類わけするためのフィールド設定だと思います。
カテゴリフィールドを選択したときの画面

ちなみにこのフィールドの設定内容は次の通りです。
カテゴリフィールドの設定内容1
カテゴリフィールドの設定内容2

実際にこのフィールドを使って文書を作ってみました。
そしてカテゴリ別ビューという形で表示したのが下図です。
カテゴリ別ビュー

これをXPagesで実現する方法って・・・書いてなかったんですよね。

ただし、実際には「タグ」を使いましょうということで記事を書いています。
タグクラウドを使ってみよう
Dojo リストテキストボックスを使ってタグっぽく表現してみよう

これはこれで便利なんですけど、すでにどんなタグが作成されているのかを確認するのが難しいんですよね。

なので、クラシックアプリと同じような形で入力できるようにしましょう。

まず、フォームを表示するためのXPageを作成しておきます。

次に、カテゴリフィールドに対応するコントロールを配置します。
カテゴリは複数選択できるようにしたいので、リストボックスコントロールを配置します。
データソースのバインドは当然、カテゴリフィールドです。
そして、「値」の項目には、フィールドの設定内容と同じように、カテゴリを取得するための式を入力します(今回は「byCategory」ビューの1列目から取得するようにします)。
また、複数設定できるようにするため 、その設定も含めます。
コントロールの部分をソース表示すると以下のような形になります。

 
  
   <![CDATA[#{javascript:@DbColumn( "", "byCategory", 1 )}]]>
  
 


これで、既存のカテゴリを選択することができるようになります。
今度は新規でカテゴリを入力させるためのコントロールを配置します。
こちらは編集ボックスコントロールを配置します。
このコントロールに入力した内容は、先ほどのカテゴリ用のフィールドにマージさせるので、
このコントロールはデータソースのバインドをする必要はありません。

データソースにバインドさせないと、文書が読込モードでも入力領域として表示されてしまうので、
可視式を設定して編集時のみ表示させるようにします。
したがってコントロールのソースは下のようになります。
ちなみに何のためのフィールドかをわかりやすくするためにplaceholderの設定もしています。
※placeholderについては、XPagesでplaceholderを実現してみるを参照のこと

 
  
  
 




これで新規入力もできるようになりました。
ただ、これでは保存してもカテゴリフィールドに反映されません。
ということで最後に[保存]ボタンにその内容を記述します。
var cat1 = getComponent( "categories1" ).getValue();
var cat2 = getComponent( "categories2" ).getValue();
var cat  = @Trim( @List( cat1, cat2 ) );
document1.replaceItemValue( "Categories", cat );
document1.save();


@List関数でcategories1コントロールとcategories2の値をマージして、@Trim関数で""を取り除いています。
その内容をCategoriesフィールドにセットして文書を保存しています。



実行結果は下図になります。
カテゴリフィールドをXPagesで実現してみた

タグクラウドを使って今風にしてもいいですし、今回のようにクラシックアプリのような形にするのもよいでしょう。
使い勝手が良いのが一番ですので、みなさんの使いやすい方を選んでくださいね。

では今日はこの辺で・・・







Notes/Dominoで困ったことがあれば、弊社にお問い合わせください。
IBM Championの私が承ります!
お問い合わせはこちらから→Lotus Notes/Domino カスタマイズとセキュリティ強化 - 株式会社エフ

2016年9月21日水曜日

XSPUserAgentのテストをしてみた

皆さん、XPages開発は順調ですか?

XPages開発をするということは、Notesクライアントで使っていたNotes DBをWeb化するというのが基本路線でしょう(XPinCといったNotesクライアントでXPagesアプリケーションを動作させる方法もありますが。

Web化する場合、使用するブラウザによっては想定していたのと違う動きをすることがあります。
そのような場合、ユーザーエージェントによってHTTPリソースを取得して、その値でブラウザ情報を判断して動きを変えるようにしたりします。

従来のNotes Webアプリでもユーザーエージェントは取得できましたが、XPagesの場合はどうすれば良いのでしょうか?

実は、XPagesでは、そのための関数が一通り用意されています。
JavaScriptのXSPUserAgentクラスを利用します。
取得方法は簡単で、SSJSで以下の記述をするだけです。

var uagt = context.getUserAgent();


これでユーザーエージェントがuagtという変数に格納されました。
後は、このクラスに設定してある関数を実行すれば結果を得ることができます。
ブラウザ名やバージョン等が取得できます。
実際に簡単な画面を作って実行したものが下図になります。

Chromeで実行したときの画面

どうでしょう。
そんなに難しくはないですよね。

たとえば、ブラウザ情報を取得したい場合は
context.getUserAgent().getBrowser()
と記述します。


ただ、一つ難点があります。
下図を見てください。同じXPagesアプリケーションをIE11で実行したときのものです。
IE11で実行したときの画面

赤枠の部分をみると、
ブラウザ情報が取得できていない。当然ブラウザのバージョン番号も取得できていない。そもそもIEであると判断されていない
ということがわかります。

このままではユーザーエージェントを使ってブラウザ情報を取得できない!ということになってしまいます。
うーん。どうしたものか・・・と悩みつつ、回避策はないものかと調べていたら、
ありましたよ。すでに。まぁ当たり前ですよね。

こちらです。
XSPUserAgent Methods Do Not Detect IE 11


さらに、すでにXSnippetsというサイトにも出ているじゃありませんか。


便利ですね。
何はともあれ、IE11でもユーザーエージェントを駆使すれば情報を取得することがわかりました。


ちなみに、このXSnippetsというサイト、日本語版があるのはご存知ですか?
XSnippets 日本語版
です。
今回のIE11の判定方法のように、みなさんが独自で作成したコードなんかを共有しましょうというサイトです。
苦労して書いたコードを他の人に簡単に提供するのは嫌かもしれませんが、自分が提供することで他のお客様の問題も同時に解決できるという風に考えればいいことだと思います。
もしかしたら、この中に自分が困っていることを解決してくれるコードもあるかもしれませんし。

ちなみにIBM Championになるためのアピールポイントとしても利用可能です(笑)

また、QAサイト等で質問して、正解が得られた場合も、そのコードを登録してくださると、他の人が利用しやすくなると思いますので、是非ご協力ください。


それでは今日はこの辺で・・・






Notes/Dominoで困ったことがあれば、弊社にお問い合わせください。
IBM Championの私が承ります!
お問い合わせはこちらから→Lotus Notes/Domino カスタマイズとセキュリティ強化 - 株式会社エフ

2016年9月19日月曜日

特定のアイテムだけコピーしてみよう

皆さんこんにちは。

三連休ですが、天気が悪いのであまり外出する気分になれません。
仕方がないので?ブログ記事を書くことにしました。

XPages関連に行きたいところですが、諸事情により、今日もLotusScriptのサンプルです。
今日はNotesDocumentクラスのCopyItemについてです。
なんかこんなメソッドのサンプルなんて書いているだろうと思っていたのですが、書いてませんでした(笑)

どうやら、私自身はあまり使ってこなかったようです。
ですが、書いてあった方が色々と役に立つこともあるでしょうから作成しておきましょう。


ちなみに、このサンプルは、自文書内の「Body」というリッチテキストフィールドの内容を新規文書にコピーするというものです。
リッチテキスト内の文字はもちろん、画像や添付ファイルまでコピーしてくれます。
決まったフォーマットのものを文書に格納しておいてそれを別の文書に格納するときなんかに使えるかな(どんなシチュエーションだ・・・)


Sub Click(Source As Button)
    On Error Goto ErrProc
    
    Dim uiws    As New NotesUIWorkspace
    Dim uidoc   As     NotesUIDocument
    Dim udoc    As     NotesDocument
    Dim ritem   As     NotesRichTextItem
    Dim session As New NotesSession
    Dim db      As     NotesDatabase
    Dim newdoc  As     NotesDocument
    
    Set uidoc  = uiws.CurrentDocument
    Set udoc   = uidoc.Document
    Set ritem  = udoc.GetFirstItem( "Body" )
    
    Set db     = session.CurrentDatabase
    Set newdoc = db.CreateDocument
    Call newdoc.ReplaceItemValue( "Form", "MainTopic" )
    Call newdoc.ReplaceItemValue( "Subject", "Bodyをコピーするために新規作成" )
    Call newdoc.ReplaceItemValue( "Categories", "テスト" )
    Call newdoc.ReplaceItemValue( "Sections", "小分類" )
    Call newdoc.CopyItem( ritem, "Body" )
    Call newdoc.Save( True, True, True )
    
    Exit Sub
    
ErrProc:
    Msgbox _
    "エラー行数:" & Cstr(Erl) & Chr$(10) & _
    "エラー番号:" & Cstr(Err) & Chr$(10) & _
    "エラー内容:" & Error, _
    0 + 16, "特定のアイテムだけコピーしてみる"
    
    Exit Sub
End Sub



サンプルはリッチテキストアイテムとしていますが、通常のアイテム(テキストフィールド、数値フィールド等)でも問題なくコピーすることができます。
色々試してみてください。




さて、サンプルを作ることの利点は、
・自分自身でコーディングすることで、どのように記述すればいいのかを覚えることができる。
・サンプルに書いたメソッド/プロパティがどのような動きをするのかが実際に分かる。
・後で備忘録のような形で利用できる。
といったところでしょうか。

このブログ記事は、私自身の備忘録として書き始めたものですが、皆さんにも同じような形で使っていただけたら幸いです。



では、今日はこの辺で・・・



Notes/Dominoで困ったことがあれば、弊社にお問い合わせください。
IBM Championの私が承ります!
お問い合わせはこちらから→Lotus Notes/Domino カスタマイズとセキュリティ強化 - 株式会社エフ


2016年9月14日水曜日

未読文書数を数えてみよう

皆さんこんにちは。
世間ではNotes/Domino 9.0.1のサポート期間が2021年9月までだとか8.5.xのサポート期間が2018年9月までだとか言ってますが、気にしません。
※9.0.1は「少なくとも」2021年9月まではサポートするよということでそこで終了とは限らないそうです。 Windows XPだってサポート終了してますが使ってる人いますよね?
IEだってOSによっては11しかサポートしてくれませんが、IE8を使ってる人いますよね?
そんなもんです。
きちんと動作してくれればそれでいいんです。
でも、せめてバージョンはあげてほしかったですね(9.0.2でも、10.0.0でもなんでもいいけど、9.0.1で延長しますというのはちょっと寂しかった)。

詳しいことはネット上にあふれているのでそちらを探して読んでみてください。


こちらのブログは通常運転です。

ということで、今日はヘルプの誤記についてのお話です。

Notes DBの未読/既読ってよくできてますよね。
ワークスペースアイコンにも未読文書数を表示することができます。
DBの未読文書数が表示されている

メールDBでは、フォルダごとに未読文書数が表示されたりします(ビューでは表示されない)。
メールDBのアウトライン(フォルダ名の横に未読文書数が表示される)

さらに、文書が未読なのか既読なのかをプログラムで判断することもできます。
文書の未読既読状態をチェックするを参照。


ここまで来たら、Notes DBの未読文書数もプログラムで数えてみたい!
ということでそんなメソッドがあるのかな?と調べてみました。
まぁ、ありますよね。えぇありましたよ。
NotesDatabaseクラスにGetAllReadDocumentsメソッド、GetAllUnreadDocumentsメソッドなるものがありました。
前者が既読文書数のコレクションで、後者が未読文書数のコレクションです。
デザイナーヘルプによると、構文は次の通り。
Set notesNoteCollection = notesDatabase .GetAllReadDocuments( [username] )


ヘルプはGetAllReadDocuments (NotesDatabase - LotusScript®)を参照
直される前に証拠の画像(笑)

へぇ。コレクションと言ったらNotesDocumentCollectionかな?と思ったら設計の一覧(NotesNoteCollection)になるんだぁ。となんとなく嫌な予感はしつつも、そういうものだろうと強引に納得しました。

ということで、プログラムを書いてみました。
Sub Click(Source As Button)
    Dim session As New NotesSession
    Dim db      As     NotesDatabase
    Dim note    As     NotesNoteCollection
    Dim uname   As     NotesName
    
    Set uname = New NotesName( session.UserName )
    Set db   = session.CurrentDatabase
    Set note = db.GetAllUnreadDocuments( uname.Canonical )
    
    Msgbox _
    uname.Common & "の未読文書数は、" & Cstr( note.Count ) & "です。", _
    0 + 64, "未読文書数の表示"
End Sub

そしたら保存できないじゃないですか!?
データ型が一致しません。と怒られて保存できない・・・

・・・もしかして、NotesDocumentCollectionなんじゃないか?
LotusScriptライブラリでプログラムを記述するとEclipseの機能により、メソッドのコードアシスタントが働き、戻り値の型などが表示されるので試しに記述してみよう!
ということで、LotusScriptライブラリで同じようにコードを記述してみて、GetAllUnreadDocumentsのコードアシスタントを確認してみました。
GetAllUnreadDocumentsのコードアシスタント


・・・えーっと。NotesDocumentCollectionって書いてありますね。
またかよ。ヘルプに間違いを書くなよっていうか、直せよ!(8.0で追加されたメソッドですが、その時からこのままだった様子)


気を取り直してプログラムを修正しました。


Sub Click(Source As Button)
    Dim session As New NotesSession
    Dim db      As     NotesDatabase
    Dim docs    As     NotesDocumentCollection
    Dim uname   As     NotesName
    
    Set uname = New NotesName( session.UserName )
    Set db   = session.CurrentDatabase
    Set docs = db.GetAllUnreadDocuments( uname.Canonical )
    
    Msgbox _
    uname.Common & "の未読文書数は、" & Cstr( docs.Count ) & "です。", _
    0 + 64, "未読文書数の表示"
End Sub


さきほどのNotes DBに仕込んで実行した結果がこちらです。
未読文書数が正しく表示されてます

ヘルプを読みましょう!と推進しているのですが、こうやって誤りがあるとなかなか推進しづらいのですが、正しい使い方を覚えるよい機会にもなるので、やっぱり読みましょう。
使ったことがないメソッドなんかは適当に書くのではなくて必ずヘルプを見てから書くようにしましょう。
そうすれば、何が悪いのかが分かるようになります。


では今日はこの辺で。





Notes/Dominoで困ったことがあれば、弊社にお問い合わせください。
IBM Championの私が承ります!
お問い合わせはこちらから→Lotus Notes/Domino カスタマイズとセキュリティ強化 - 株式会社エフ


2016年9月7日水曜日

リッチテキストに文字揃えを設定してから文字列を追加する

みなさん、こんにちは。

今日、9月7日はチャルメラが発売された日らしいです。まぁ、私は食べないので関係ないのですが・・・

さて、今日はqA9 for ICS Developersに投稿された質問に対してのサンプルを作成してみます。

お題は、リッチテキストフィールドに文字列を追加する際、右寄せの状態でできるか?
というものです。

答えはXスニペットというサイトに載せてありますので、参照してみてください。

こちら→文字揃えを設定してリッチテキストに文字列を追加するです。



ちなみに、リッチテキストに表を作成するのを含めたサンプルはこちら。
表自体の位置を設定することはできなさそう。
表のプロパティ

Function funcCreateRichText() As Boolean
    funcCreateRichText = False
    
    Dim session   As New NotesSession
    Dim db        As     NotesDatabase
    Dim doc       As     NotesDocument
    Dim ritem     As     NotesRichTextItem
    Dim rpara1    As     NotesRichTextParagraphStyle
    Dim rpara2(2) As     NotesRichTextParagraphStyle
    Dim uiws      As New NotesUIWorkspace
    
    On Error GoTo ErrProc
    
    '新規文書の作成
    Set db    = session.CurrentDatabase
    Set doc   = db.CreateDocument
    
    '文書情報の生成
    Call doc.ReplaceItemValue( "Form", "fmRichText" )
    Call doc.ReplaceItemValue( "Subject", "自動作成文書_" & Format( Now, "yyyymmddhhnnss" ) )
    
    'リッチテキスト段落属性の生成
    Set rpara1 = session.CreateRichTextParagraphStyle()
    
    'リッチテキストの生成(1)・・・リッチテキストに対して文字列を追加する
    Set ritem = New NotesRichTextItem( doc, "Body" )
    rpara1.Alignment = ALIGN_RIGHT
    Call ritem.AppendParagraphStyle( rpara1 )
    Call ritem.AppendText( "1行目:この行は右寄せで作成しています。" )
    rpara1.Alignment = ALIGN_CENTER
    Call ritem.AppendParagraphStyle( rpara1 )
    Call ritem.AppendText( "2行目:この行は中央寄せで作成しています。" )
    rpara1.Alignment = ALIGN_LEFT
    Call ritem.AppendParagraphStyle( rpara1 )
    Call ritem.AppendText( "3行目:この行は左寄せで作成しています。" )
    Call ritem.AddNewLine( 1 )
    
    'リッチテキストの生成(2)・・・リッチテキストに対して表を追加する
    Set rpara2(0) = session.CreateRichTextParagraphStyle()        '1列目用
    Set rpara2(1) = session.CreateRichTextParagraphStyle()        '2列目用
    Set rpara2(2) = session.CreateRichTextParagraphStyle()        '3列目用
    
    rpara2(0).FirstLineLeftMargin = RULER_ONE_CENTIMETER * 0.15
    rpara2(0).LeftMargin          = RULER_ONE_CENTIMETER * 0.15
    rpara2(0).RightMargin         = RULER_ONE_CENTIMETER * 4
    rpara2(1).FirstLineLeftMargin = RULER_ONE_CENTIMETER * 0.15
    rpara2(1).LeftMargin          = RULER_ONE_CENTIMETER * 0.15
    rpara2(1).RightMargin         = RULER_ONE_CENTIMETER * 6
    rpara2(2).FirstLineLeftMargin = RULER_ONE_CENTIMETER * 0.15
    rpara2(2).LeftMargin          = RULER_ONE_CENTIMETER * 0.15
    rpara2(2).RightMargin         = RULER_ONE_CENTIMETER * 8
    Call ritem.AppendTable( 2, 3, , , rpara2 )
    
    '作成した文書の保存
    Call doc.Save( True, True, True )
    
    'ビューのリフレッシュ
    Call uiws.ViewRefresh()
    
    funcCreateRichText = True
    Exit Function
    
ErrProc:
    Error Err, Error
    
    Exit Function
End Function



LotusScriptでリッチテキストを操作する方法は他にも色々ありますし、当ブログでも紹介していますので、併せて読んでいただくとより理解が深まるかと思います。



Notes/Dominoで困ったことがあれば、弊社にお問い合わせください。
IBM Championの私が承ります!
お問い合わせはこちらから→Lotus Notes/Domino カスタマイズとセキュリティ強化 - 株式会社エフ

2016年9月6日火曜日

LS2JでREST APIを実行してみよう

皆さん、こんにちは。

9月に入ってしまいました。
だんだんと日が落ちる時刻が早くなってきてますね。18時を過ぎると暗くなってきてます。
こうやって夏は過ぎていき、秋が来るんですね。

さて、今日もREST APIについてのお話です。
ただし、今回はXPagesではなく、Notesクライアントからの実行ができるように進めていきます。

REST APIはHTTP通信を行いますので、Notesクライアントからはそのまま(@関数やLotusScriptを使う)では実行できません。

そこで、Javaプログラムを組んでそれを実行することになります。
NotesクライアントからJavaプログラムを実行するにはいくつかの方法があります。

  1. Webページを表示させて、その中でJavaプログラムを実行する
  2. Javaエージェントを作成して、LotusScriptから呼び出す
  3. LS2Jを使ってLotusScriptからJavaを実行する


1.はNotesクライアントはWebブラウザも内包されているのを利用しているものです。

2.はソルクシーズの吉田さんもブログ記事にしている(Notes から MQTT を使って Publish する(Quickstart : Watson Internet of Things Platform))ものですね。
もっとも、こちらの記事ではRESTではなく、IoTを使うためのMQTTをJavaエージェントで実行していますが。

3.は古い記事ではありますが、「Notesサポートのつぶやき」というブログのLS2J : LotusScript でJavaのクラスを呼び出してみるにあるLotusScriptを拡張してJavaプログラムを呼び出せるという方法をつかっています。

いずれもJVMを使うことになるので、メモリ使用量に気を付けなければいけませんが、それでもNotesクライアントから実行できるというのはなかなか面白いものだと思います。

今日は、これらのうち、「3.LS2Jを使ってLotusScriptからJavaを実行する」という方法でREST APIを使ったプログラムを実装してみます。



実装するのはお決まりの郵便番号検索です。
郵便番号を入力したら、郵便番号データ格納したNotes DBにREST APIで接続して、該当する住所情報を取得してくるというものにします(XPagesでのREST APIの紹介時に使用したものと同等ですNotes/Domino でREST APIを使ってみよう-後半-を参照)。

今回のサンプル画面はこんな感じです。
Notes DBの郵便番号検索画面

郵便番号フィールドに郵便番号を入力して、[検索]ボタンをクリックすると該当する住所情報が「都道府県名」「市区町村名」「町域名」に入ってくるという形です。

では、早速プログラムの中身を見ていきましょう。
※実装順序は無視しています。

1.[検索]ボタン

Option Declare
Use "LibRESTAPI"

Sub Click(Source As Button)
    Dim uiws  As New NotesUIWorkspace
    Dim uidoc As     NotesUIDocument
    Dim udoc  As     NotesDocument
    Dim adrs  As     TypeAddress
    
    Set uidoc = uiws.CurrentDocument
    Set udoc  = uidoc.Document
    
    If SearchAddress( udoc.ZIPNO(0), adrs ) = False Then
        Msgbox "住所の検索に失敗しました。", 0 + 16, "郵便番号検索"
        Exit Sub
    Else
        Call udoc.ReplaceItemValue( "PREFECTURES", adrs.Prefectures )
        Call udoc.ReplaceItemValue( "CITIES", adrs.Cities )
        Call udoc.ReplaceItemValue( "ADDRESS", adrs.Address )
    End If
End Sub

フォーム上に細々とプログラムを書くのが好きではないので、最小限の形にしています。
NotesUIDocumentクラスのメソッドを使用して、入力した郵便番号を取得して、それを引数にしてSearchAddress()という関数を呼び出しています。
この関数の戻り値が成否と住所情報で、成功していたら住所情報を画面上の文書にセットしています(計算結果フィールドにしているので、NotesDocumentクラスのメソッドを使ってセットしています)。
ここは、よくある?LotusScriptのプログラムだと思いますので、そんなに難しくはないと思います。


2.LS2Jの関数

Option Public
Option Declare

UseLSX "*javacon"
Use "NotesREST"
Use "ClassEnvironment"

Type TypeAddress
    Prefectures As String        '都道府県名
    Cities      As String        '市区町村名
    Address     As String        '町域名
End Type

Function SearchAddress( zipno As String, adrs As TypeAddress ) As Boolean
    SearchAddress = False
    On Error GoTo ErrProc
    
    Dim mySession  As New JavaSession
    Dim myClass    As     JavaClass
    Dim varAddress As     Variant
    Dim endpoint   As     String
    Dim cEnv       As     cEnvironment
    
    '入力チェック
    If zipno = "" Then
        Exit Function
    End If
    
    '環境設定文書オブジェクトの取得
    Set cEnv = New cEnvironment()
    
    'Javaクラスの取得
    Set myClass  = mySession.GetClass( "jp.co.effectforce.NotesREST" )
    endpoint     = cEnv.EndPoint
    varAddress   = myClass.searchAddress( endpoint, zipno )
    
    If varAddress(0) = "" Then
        Exit Function
    End If
    adrs.Prefectures = varAddress(0)
    adrs.Cities      = varAddress(1)
    adrs.Address     = varAddress(2)
    
    SearchAddress = True
    Exit Function
    
ErrProc:
    MsgBox _
    "エラー行数:" & CStr(Erl) & Chr$(10) & _
    "エラー番号:" & CStr(Err) & Chr$(10) & _
    "エラー内容:" & Error, 0 + 16, "LS2JによるREST API"
    
    Exit Function
End Function

こちらがLS2Jのプログラムです。
ポイントはいくつかありますが、まずはUseLSX "*javacon"という記述が必要なこと。これはLotusScriptからJavaの関数を実行できるようにするためのものです。

次に、下記変数の定義。
Dim mySession  As New JavaSession
Dim myClass    As     JavaClass

変数名は任意ですが、型は決まり事ですので、このまま覚えても差し支えないでしょう。
JavaSessionはJVMにアクセスするためのクラスです。NotesSessionと同等のものと考えてよいかと思います。
JavaClassはその名の通り、Javaのクラスです。既存のJavaのメソッドを実行することもできますし、自分でJavaクラスを作成して(後述)、そのメソッドを実行することもできます。
java.lang.*やjava.util.*クラスの関数であれば、そのままLotusScriptに記述して使えそうです。
(どこまでが標準のままで使えるかについてはわかってません。ごめんなさい・・・)


JavaClassに定義したのは、自作した郵便番号検索用のREST APIのクラスです。
それがこの文になります。
Set myClass  = mySession.GetClass( "jp.co.effectforce.NotesREST" )

実際に、REST APIで郵便番号を検索しているのが、下記のメソッドです。
endpointには、郵便番号を取得するためのURLが格納されています。
varAddress   = myClass.searchAddress( endpoint, zipno )


3.自作したJavaクラス

スクリプトライブラリは、LotusScript以外にもJavaやJavaScriptも作成することができます。
LS2Jなので、Javaのスクリプトライブラリを作成します。
スクリプトライブラリ作成画面

名前を入力して、タイプを「Java」にして、[OK]をクリックすると、
Javaライブラリコンテンツの画面になるので、Untitle.javaをダブルクリックして、ソースのエディタ画面を開きます。
すると、
public class Untitled { 
}

だけが表示されたさびしい画面になるので、適宜変更します。
なお、今回のソースは以下のような形にしてみました。
package jp.co.effectforce;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.*;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;

public class NotesREST {
    public static String[] searchAddress( String endpoint, String zipno ) throws Exception {
        String[] adrs = new String[3];        // Output用住所情報格納変数
        try {
            // Initialize
            adrs[0] = "";
            adrs[1] = "";
            adrs[2] = "";
            
            // REST API
            String strUrl = endpoint + "?search=FIELD%20zip7%20CONTAINS%20" + zipno;
            URL url = new URL( strUrl );
            HttpURLConnection con = (HttpURLConnection)url.openConnection();
            con.setRequestMethod( "GET" );
            con.addRequestProperty( "Content-Type", "application/json; charset=utf-8" );
            con.setInstanceFollowRedirects( false );
            con.setDoInput( true );
            con.connect();
            
            int rc = con.getResponseCode();
            if (200 != rc) throw new Exception( "ErrorCode:" + rc + "/ErrMessage:" + con.getResponseMessage() );
            
            BufferedReader reader = new BufferedReader( new InputStreamReader(con.getInputStream()) );
            StringBuilder buffer = new StringBuilder(2048);
            String line = null;
            while (null != (line = reader.readLine())) {
                buffer.append( line ).append('\n');
            }
            String result= buffer.toString();
            
            // JsonFactoryをもとにJsonParserの取得
            JsonFactory factory = new JsonFactory();
            JsonParser parser = factory.createParser( result );
            
            // 配列で返ってくるのでそれを見越した処理とする
            if ( parser.nextToken() == JsonToken.START_ARRAY ) {
                while ( parser.nextToken() != JsonToken.END_ARRAY ) {
                    // 各オブジェクトの処理
                    if ( parser.getCurrentToken() == JsonToken.START_OBJECT ) {
                        while ( parser.nextToken() != JsonToken.END_OBJECT ) {
                            String pname = parser.getCurrentName();
                            parser.nextToken();
                            // Prefectures or Cities or Addressの場合のみ処理をする
                            if ( "Prefectures".equals( pname ) ) {
                                adrs[0] = parser.getText();
                            } else if ( "Cities".equals( pname ) ) {
                                adrs[1] = parser.getText();
                            } else if ( "Address".equals( pname ) ) {
                                adrs[2] = parser.getText();
                            } else {
                                parser.skipChildren();
                            }
                        }
                    } else {
                        parser.nextToken();
                    }
                }
            }
            
            // disconnect
            con.disconnect();
            
            return adrs;
            
        } catch( Exception e ) {
            System.out.println( "getMessage= " + e.getMessage() );
            adrs[0] = "";
            adrs[1] = "";
            adrs[2] = "";
            return adrs;
        }
    }
}


上記のソースの中で
URL url = new URL( strUrl );
・・・
String result= buffer.toString();

この辺りがREST APIになります。
endpointに指定したURLに対して、「GET」でhttp通信をしているくらいです。
その後、返ってきた結果を行単位で読み込んで、resultという文字列変数に格納しています。
この格納された文字列はJSON形式のデータです。


そこから下の行はREST APIで取得したJSONデータをJavaで解析をしています。
ここで、一つ問題になるのが、JavaでJSONを扱うには、そのままではできないということです(Java8で実装予定らしいけど、どうなったんだろ?)。
そこで、JacksonというJavaのライブラリを利用することにします。
今回はJacksonのうち、coreである「jackson-core-2.3.5.jar」をダウンロードして使用しています。

※Jasksonライブラリの使い方についてはGoogleで検索してみてください。

JSONデータをJavaで解析していき、必要な情報(Prefectures、Cities、Address)を配列に格納して、返しています。



このようにLS2Jを使えば、NotesクライアントからもJavaプログラムを実行することができます。
さらにJavaプログラムを作成すれば、NotesクライアントからもREST APIを実行することがわかっていただけたかと思います。

Notes DBをXPagesするのは大変なんだけど、Webサービスを使ってみたい!という方はこういったことにもチャレンジしてみてはいかがでしょうか?





なお、LS2Jについては、Domino Designerのヘルプに詳しい解説が出ていますので、熟読することをお勧めします。こちらを参照->LS2J の概要



それでは今日はこの辺で・・・


Notes/Dominoで困ったことがあれば、弊社にお問い合わせください。
IBM Championの私が承ります!
お問い合わせはこちらから→Lotus Notes/Domino カスタマイズとセキュリティ強化 - 株式会社エフ

2016年8月27日土曜日

XPages研究会のハンズオンをまとめましたよ(2)

はい、こんにちは。

前回(XPages研究会のハンズオンをまとめましたよ(1))の続きです。

前回は、Node-REDアプリ経由でTwitterのつぶやきデータをIBM Bluemix上のXPages NoSQL Databaseに格納するところまで実装しました。


次は、XPages NoSQL Databaseの内容をXPagesアプリで表示してみましょう。ということでXPagesアプリを作成します。

5.xspアプリを作成する

  • Bluemixのダッシュボードに戻り、「Cloud Foundryアプリ」にある[アプリの作成]をクリックする
  • 「どのような種類のアプリを作成しますか?」を聞かれるので、[Web]をクリックする
  • 「どのように開始しますか?」を聞かれるので、[XPages]をクリックする
  • 画面下にXPagesの説明が表示されるので読んだら、[続行]をクリックする
  • 「新規アプリはどのような名前にしますか?」と聞かれるので、[アプリ名]にアプリケーションの名前を入力する(*1)
  • [完了]をクリックする
  • アプリケーションのステージングが完了するのを待つ
  • 「アプリは実行中です。http://~」の表示になったら、ダッシュボードに戻る
  • 実行中になっているxspアプリをクリックする
  • アプリケーションの画面になるので、[サービスまたはAPIのバインド]をクリックする
  • 「アプリケーションへのサービスの追加」画面が表示されるので、作成したXPages NoSQL Databaseを選択して[追加]をクリックする
  • 再ステージが必要という画面が表示されるので[再ステージ]をクリックする
  • 再ステージが完了すると、アプリケーションの画面にXPages NoSQL Databaseが追加されているのが確認できる

*1 任意で良いが、Bluemix全体でユニークである必要があるので、自分のものと分かり易いような名前をつけること


これでXPages on Bluemixとしての準備はできましたが、まだXPagesアプリをきちんと作成していません。
ここでようやくIBM Domino Designerを使ってXPagesアプリを作成します。

6.XPagesアプリを作成する

  • 前回の記事の「2.XPages NoSQL Databaseサービスを作成」でダウンロードしたBluemix用のNotes User IDを使ってXPagesアプリケーションを作成する
スターターコードをダウンロードすることによって、ある程度作成されたNotesDBを利用することもできますが、大したものを作成するわけではないので、今回は新規にNotes DBを作成します。

  • まず、事前に作成してあるXPages NoSQL Databaseで作成したフォームを表示するためのXPageを作成する
フォームの情報を表示するので、Domino文書のデータソースを定義します。
まず、データソースはIBM Bluemix上にあるXPages NoSQL Databaseなので、現在作成しているNotes DBとは別の場所にあります。そのため、データソースも「現在のアプリケーション」ではなく、計算して求める必要があります。
計算式は次のようになります。
bluemixContext.getDataService().findDatabaseName();
というのが、Bluemix上のNotes DBを探すための関数です。
xspアプリにXPages NoSQL Databaseをバインドしておくと、この関数によりそのNotes DBのファイル名を取得することができるようです。

あとは、フィールドを表示するためのコントロールを2つ定義して終わりです。
今回は編集する必要はないので、「計算結果コントロール」を配置しています。
  • 次にビューを表示するためのXPageを作成する
今回はサンプルということでビューコントロールを配置しただけのものにしました。
ここで注意したいのが、データソースの定義とビュー列の設定です。

データソースの定義はフォームの時と同じように、
bluemixContext.getDataService().findDatabaseName();
で取得するようにします。
この方法でデータソースを定義すると、ビュー名は自動で取得できないため、手動で入力する必要があります。

また、これにより、ビュー列も自動で取得することができないため、手動で追加する必要があります。
ソース画面で直接入力することもできますが、GUI上での操作をする場合、ビューコントロール上でマウスの右クリックをして[列の追加]メニューを実行すれば良いです。
当然、ビュー列の値も手動で設定する必要があります。

さらに、「実行時に、選択した文書を開くために使用」の項目の値を先ほど作成したフォーム用のXPageの名前に変更します。


ビューが作成できたらXPageを保存します。
  • XPageを作成したらアプリケーションビューで[IBM Bluemix Manifest]をダブルクリックする
  • IBM Bluemix Manifestを作成するウィザードを起動するかどうか聞いてくるので、[はい]をクリックする

ここからはいよいよBluemixにxspアプリをアップロードするための作業に入ります。
IBM Domino Desigerのプリファレンス設定でBluemixとの接続設定はできるようなっているはずですが、どのアプリケーションと関連付けするのかといった設定をすることになります。
といってもウィザードの設定どおりにすれば簡単にできます。
  • デプロイ用のディレクトリの場所を聞いてくるので任意のフォルダを指定する
  • [次へ]をクリックする
任意のフォルダとなっていますが、後で分からなくならないように、Notesが格納されている場所とは別のフォルダにすると良いでしょう。
  • デプロイ方法を聞いてくるので、そのまま[次へ]をクリックする
デプロイするのに、Notes DBのコピーを配置するのかレプリカを配置するのかを聞いてきます。
コピーを推奨しているので、そのままにしておきましょう。
  • デプロイするスペースを聞いてくるので、xspアプリがあるスペースを選択して[次へ]をクリックする
ここでは自分が作成したxspアプリがBluemixのどのスペースにあるのかを聞いてきます。
スペースが見当たらない場合は、Bluemixの別のリージョン(地域:米国南部、英国、シドニーのいずれか)に作成している可能性があるので、IBM Domino DesignerのプリファレンスでBluemixのURLを確認してください。
  • アプリケーションを作成するのか既存のに置換するのか聞いてくるので先ほど作成したxspアプリを選択して[終了]をクリックする
ここでxspアプリの名前を選択します。忘れてしまった!という場合は、Bluemixのダッシュボードで確認しましょう。
たくさんアプリを作成している場合は間違えないように注意してくださいね。
  • IBM Bluemix Manifestが作成されたので、[ESC]を押して画面を閉じる

これでこのNotes DBとBluemixのアプリの連携設定ができました。
この作業(IBM Bluemix Manifestの作成)は一つのNotes DBにつき一度だけ設定すればよいものです。
  • アプリケーションを右クリックして[IBM Bluemix]-[Deploy Application]をクリックする

この作業を行うと、Notes DBがBluemix上にデプロイされます。ここはかなり時間がかかりますので、気長に待ちましょう。

  • デプロイに成功すると、「Deployment Success」というメッセージが表示されるので[OK]をクリックする

このメッセージが表示されたら、IBM Bluemix上でアプリケーションが稼働している状態になっています。
ダッシュボードでアプリの画面を開いてxspアプリのURLをクリックします。
すると、XPagesアプリケーションが別ウィンドウで開きます。



起動したばかりなので、ビューには何も表示されていませんが、Twitterでつぶやけば、その内容が表示されるようになります。
(当然、Node-REDのアプリも起動しておく必要があります)


ということで、XPages研究会の7-8月のハンズオンの内容を2回に分けて紹介してみました。
XPages研究会のメンバーでまだ出来上がってないという方や、IBM BluemixとXPagesの連携に興味があるな。という方は、この記事を元に演習してみてくださったら嬉しい限りです。


では、今日はこの辺で・・・