IRISのInteroperability機能を使ったWindows共有フォルダでのファイル連携
開発者の皆さん
こんにちは。
Windows共有しているリモートサーバに出力されたファイルでデータ連携する際、セキュリティ上、資格情報が必要となるケースが良くあるかと思います。いままでCachéで連携していた時には%ZSTARTルーチンや常駐プロセスのルーチンにて「net useコマンド」を実行されていたかと思いますが、IRISではInteroperability機能が使用できますので、前回の記事で作成したビジネスサービスクラスを元に、資格情報を使ってWindows共有フォルダにアクセスできる機能を追加したいと思います。
仕組み
ビジネスサービスが起動、停止する際に呼び出されるOnInit()、OnTearDown()メソッドにnet useコマンドを埋め込み、指定されている資格情報を使ってnet useコマンドで共有フォルダへの接続、切断を行います。
認証情報設定パラメータ追加
ビジネスサービスの設定画面で認証情報を選択できるよう、以下のようにCredentialsプロパティ、SETTINGSパラメータをTest.BS.ImportMasterクラスに設定します。
/// 共有アクセス用Credential Property Credentials As %String; /// ビジネスサービスにてCredentialを選択させるUIを指定 Parameter SETTINGS = "Credentials:Basic:credentialsSelector";
OnInit()メソッドの作成
OnInit()メソッドではファイルパスがWindows共有フォルダ(ファイルパスが\\で始まる)の場合、ExecNetUseメソッドを呼び出し、Net useコマンドで共有ディレクトリへの接続を行います。Net useコマンドが失敗した場合、ExecNetUserメソッドを呼び出し、共有ディレクトリの切断を行います。
Method OnInit() As %Status { // ファイルパスが\\で始まる場合でかつCredentialsプロパティが空文字でなければ、共有ディレクトリに接続 if $extract(..Adapter.FilePath,1,2)="\\"&&(..Credentials'="") { // 認証情報を検索 set tCredential=##class(Ens.Config.Credentials).%OpenId(..Credentials) if '$isobject(tCredential) { // プロパティCredentialsに入力された認証情報が存在しない場合、終了 Set tSC=$$$EnsError($$$EnsErrNoCredentials,..Credentials) Quit tSC } // 共有ディレクトリへの接続 set tSC=..ExecNetUse($piece(..Adapter.FilePath,"\",1,4),tCredential.Username,tCredential.Password) if $$$ISERR(tSC) { $$$LOGSTATUS(tSC) // エラーが発生した場合、念のため共有ディレクトリの切断 set tSC2=..ExecNetUse($piece(..Adapter.FilePath,"\",1,4),,,1) if $$$ISERR(tSC2) $$$LOGSTATUS(tSC2) set %objlasterror=tSC quit tSC } $$$LOGINFO("共有ディレクトリ "_$piece(..Adapter.FilePath,"\",1,4)_" に接続しました") } Quit $$$OK }
ExecNetUseメソッドは以下の通りです。ここではエラー出力をファイルに出力し、戻り値が0でない場合、ファイルから出力メッセージを読み込み、エラーメッセージとして返しています。
ClassMethod ExecNetUse(sharefolder As %String, username As %String = "", password As %String = "", deleteflg As %Boolean = 0) As %Status { // エラーログファイル名を取得 set curdir=$SYSTEM.Process.CurrentDirectory() set errlog=curdir_"netuse_"_$job_".log" set tSC=$$$OK try { if deleteflg { // Net useコマンドで切断する set sts=$zf(-1,"net use "_sharefolder_" /delete 2> """_errlog_"""") } else { // Net useコマンドで指定されたユーザ名、パスワードで接続する set sts=$zf(-1,"net use "_sharefolder_" "_password_$select(username'="":" /user:"_username,1:"") _" /persistent:NO 2> """_errlog_"""") } quit:sts=0 // 正常終了ならば終了 // ログの読み込み set stream=##class(%FileCharacterStream).%New() set stream.Filename=errlog set msg=$translate(stream.Read(),$char(10,13)," ") // 改行コードを消去 kill stream set tSC=$$$ERROR(5001,"net use コマンドでエラーが発生しました 戻り値="_sts_" Msg="_msg) } catch { set tSC=$$$ERROR(5001,"net use コマンド実行時にエラーが発生しました Err="_$zerror) } // ログファイルの削除 do ##class(%File).Delete(errlog) quit tSC }
OnTearDown()メソッドの作成
OnTearDown()メソッドはビジネスサービス停止時に呼ばれます。
ファイルパスがWindows共有フォルダ(ファイルパスが\\で始まる)の場合、ExecNetUseメソッドを呼び出し、Net useコマンドで共有ディレクトリの切断を行い、継承元の処理を行います。
Method OnTearDown() As %Status { // 共有ディレクトリの切断 set tSC=..ExecNetUse($piece(..Adapter.FilePath,"\",1,4),,,1) if $$$ISERR(tSC) $$$LOGSTATUS(tSC) if $$$ISOK(tSC) $$$LOGINFO("共有ディレクトリ "_$piece(..Adapter.FilePath,"\",1,4)_" を切断しました") // 継承元の処理を実行 quit ##super() }
クラスのコンパイル
プロパティやメソッドを追加した Test.BS.ImportMaster クラスをコンパイルします。
認証情報の設定
システム管理ポータルの「Interoperability」「構成」「認証情報」メニューをクリックし、認証情報を設定します。
以下の画面が表示されますので、右下の「新規」ボタンをクリックし、「ID」「ユーザ名」「パスワード」を入力し、「保存」ボタンをクリックします。
余談になりますが、当初「ユーザ名」欄をリモートサーバのユーザ名のみにしているとnet useコマンドが時々失敗し、接続できなくなってハマってしまいました 「ユーザ名」欄は<NetBIOSコンピュータ名>\<ユーザ名> または <ドメイン名>\<ユーザ名> にしたほうがよいかと思います。
ビジネスサービスの追加
最後にビジネスサービスの設定を行います。
管理ポータルの「InterOperability」「構成」「プロダクション」をクリックすると、以下のようなプロダクション構成画面が表示されますので、サービスの右にある「+」ボタンをクリックします。
以下のダイアログボックスが表示されますので、「サービスクラス」には、先ほど修正したクラス「Test.BS.ImportMaster」とサービス名「FileServer連携」を入力、「有効にする」をチェックし、「OK」ボタンをクリックします。(サービス名は任意の名前で構いません)
ビジネスサービスが追加されましたので、以下の画面にて、作成したビジネスサービス「FileServer連携」をクリックし、「設定」タブをクリック、設定を行います。
ここで、以下の項目を入力し「適用」ボタンをクリックします。
- ファイルパス 監視するリモートサーバのディレクトリ。
- アーカイブパス 読み込んだファイルを格納するディレクトリ。
- 認証情報 先ほど作成した認証情報のIDをドロップダウンリストから選択します。
プロダクションの開始
最後にプロダクション構成画面の「開始する」ボタンをクリックし、プロダクションを開始します。
これで、共有ディレクトリに対してファイルが出力されると、Test.BS.ImportMasterクラスのOnProcessInputメソッドが呼び出され、共有ディレクトリにあるファイルの取り込み処理が行えるようになります。取り込み処理については前回の記事をご参照ください。
また、今回作成したクラスやルーチンはこちらにアップロードしています。
ご質問等ございましたら、お気軽に書き込んでください。
よろしくお願いします。