検索

クリアフィルター
記事
Toshihiko Minamoto · 2021年4月5日

WebSocketのチュートリアル

## はじめに Webで行われるサーバーとクライアント間のほとんどの通信は、リクエストとレスポンスの構造に基づいており、 クライアントがサーバーにリクエストを送信すると、サーバーがそのリクエストに対するレスポンスを送信します。 WebSocketプロトコルは、サーバーとクライアント間の双方向通信チャンネルを提供するプロトコルで、サーバーがリクエストを受信しなくても、クライアントにメッセージを送信することができます。 WebSocketプロトコルと、InterSystems IRISでの実装についての詳細は、以下のリンクをご覧ください。 * [WebSocketプロトコル](https://tools.ietf.org/html/rfc6455) * [InterSystems IRISでのWebSocketsに関するドキュメント](https://docs.intersystems.com/irislatestj/csp/docbook/DocBook.UI.Page.cls?KEY=GCGI_websockets) このチュートリアルは、「[非同期WebSocket -- クイックチュートリアル](https://community.intersystems.com/post/asynchronous-websockets-quick-tutorial)」を、Caché 2016.2以上とInterSystems IRIS 2018.1以上向けに更新したものです。 #### *非同期動作と同期動作* InterSystems IRISでは、WebSocket接続を同期的または非同期的に実装することができます。 クライアントとサーバー間のWebSocket接続がどのように動作するかは、%CSP.WebSocketクラスの「SharedConnection」プロパティによって決まります。 * SharedConnection=1: 非同期動作 * SharedConnection=0: 同期動作 クライアントとInterSystems IRISインスタンスがホスティングされているサーバーとの間のWebSocket接続には、IRISインスタンスとWebゲートウェイとの間のコネクションが含まれます。 WebSocketの同期動作では、そのコネクションはプライベートチャンネルが使用されますが、 非同期動作では、複数のWebSocketクライアントで、IRISインスタンスとWebゲートウェイとの間のコネクションが共有されます。 WebSocketの非同期動作は、各クライアントを処理するWebゲートウェイとIRISインスタンス間のコネクションを排他的に行う必要がないため、同一のサーバーに多数のクライアントが接続する場合に、そのメリットを発揮します。 このチュートリアルでは、WebSocketの非同期動作を行います。 したがって、開いているすべてのチャットウィンドウは、Webゲートウェイと、WebSocketサーバークラスをホストするIRISインスタンス間のコネクションを共有することになります。 ## チャットアプリケーションの概要 WebSocketの「hello world」は、ユーザーがそのアプリケーションにログインしているすべてのユーザーにブロードキャストされるメッセージを送信できるチャットアプリケーションです。 このチュートリアルでは、チャットアプリケーションには次のコンポーネントが含まれます。 * サーバー: %CSP.WebSocketを継承したクラスに実装されています。 * クライアント: CSPページで実装されています。 このチャットアプリケーションの実装では、次の内容を実現します。 * ユーザーは、開いているすべてのチャットウィンドウにメッセージをブロードキャストできます。 * オンラインユーザーは、開いているすべてのチャットウィンドウの「オンラインユーザー」リストに表示されます。 * ユーザーは、「alias」キーワードで始まるメッセージを作成することで、ユーザー名を変更できます。このメッセージはブロードキャストされませんが、「オンラインユーザー」リストの内容を更新します。 * ユーザーがチャットウィンドウを閉じると、「オンラインユーザー」リストから削除されます。 チャットアプリケーションのソースコードについては、こちらの[GitHubリポジトリ](https://github.com/intersystems/InterSystems-WebSockets)をご覧ください。 ## クライアント チャットアプリケーションのクライアント側は、チャットウィンドウのスタイル定義、WebSocket接続の宣言、サーバー間との通信を処理するWebSocketのイベントとメソッド、およびサーバーに送信されるメッセージをパッケージ化し、受信メッセージを処理するヘルパー関数を含むCSPページによって実装されます。 まず、アプリケーションが、JavaScript WebSocketライブラリを使用して、WebSocket接続をどのように初期化するのか確認しましょう。 ```javascript ws = new WebSocket(((window.location.protocol === "https:")? "wss:":"ws:") + "//"+ window.location.host + "/csp/user/Chat.Server.cls"); ``` `new` は、WebSocketクラスの新しいインスタンスを作成します。 これにより、「wss」(WebSocket通信チャンネルにTLSを使用することを示します)または「ws」プロトコルを使って、サーバーにWebSocket接続が開きます。 サーバーは、`Chat.Server` クラスを定義するウェブサーバーのポート番号とインスタンスのホスト名で指定されてます(この情報は `window.location.host` 変数に格納されます)。 サーバークラスの名前(`Chat.Server.cls`)は、サーバー上のリソースのGETリクエストとして、WebSocketの開始URIに含まれます。 WebSocket接続の確立に成功すると `ws.onopen` イベントが発生し、**_接続中_**から**_接続_**に状態が移行します。 ```javascript ws.onopen = function(event){ document.getElementById("headline").innerHTML = "CHAT - CONNECTED"; }; ``` このイベントにより、チャットウィンドウの見出しが変更され、クライアントとサーバーが接続されていることが示されるようになります。 ### *メッセージの送信* ユーザーがメッセージを送信するアクションによって、`send` 関数がトリガーされます。 この関数は `ws.send` メソッドを囲むラッパーとして機能し、クライアントのメッセージをWebSocket接続を介してサーバーに送信する仕組みが含まれます。 ```javascript function send() { var line=$("#inputline").val(); if (line.substr(0,5)=="alias"){ alias=line.split(" ")[1]; if (alias==""){ alias="default"; } var data = {} data.User = alias ws.send(JSON.stringify(data)); } else { var msg=btoa(line); var data={}; data.Message=msg; data.Author=alias; if (ws && msg!="") { ws.send(JSON.stringify(data)); } } $("#inputline").val(""); } ``` `send` は、サーバーに送信される情報(エイリアスの更新または一般的なメッセージ)をJSONオブジェクトにパッケージ化し、送信される情報の種類に応じたキー/値ペアを定義します。 `btoa` は、一般メッセージの内容を、base-64でエンコードされたASCII文字列に変換します。 ### *メッセージの受信* クライアントがサーバーからメッセージを受信すると、`ws.onmessage` イベントがトリガーされます。 ```javascript ws.onmessage = function(event) { var d=JSON.parse(event.data); if (d.Type=="Chat") { $("#chat").append(wrapmessage(d)); $("#chatdiv").animate({ scrollTop: $('#chatdiv').prop("scrollHeight")}, 1000); } else if(d.Type=="userlist") { var ul = document.getElementById("userlist"); while(ul.firstChild){ul.removeChild(ul.firstChild)}; $("#userlist").append(wrapuser(d.Users)); } else if(d.Type=="Status"){ document.getElementById("headline").innerHTML = "CHAT - connected - "+d.WSID; } }; ``` クライアントが受信するメッセージの種類(「チャット」、「ユーザーリスト」、「ステータス」)に応じて、`onmessage` イベントによって、`wrapmessage` または `wrapuser` が呼び出され、チャットウィンドウの該当するセクションに受信データを取り込みます。 受信メッセージがステータス更新であれば、チャットウィンドウのステータスの見出しがWebSocket IDで更新されます。このIDは、チャットウィンドウに関連付けられた双方向WebSocket接続を識別するものです。 ### *その他のクライアントコンポーネント* クライアントとサーバー間の通信でエラーが発生すると、WebSocketの `onerror` メソッドがトリガーされ、エラーの発生を通知するアラートの発行とページのステータス見出しの更新が行われます。 ```javascript ws.onerror = function(event) { document.GetElementById("headline").innerHTML = "CHAT - error"; alert("Received error"); }; ``` クライアントとサーバー間のWebSocket接続が閉じると、`onclose` メソッドがトリガーされ、ステータスの見出しが更新されます。 ```javascript ws.onclose = function(event) { ws = null; document.getElementById("headline").innerHTML = "CHAT - disconnected"; } ``` ## サーバー チャットアプリケーションのサーバー側は、`%CSP.WebSocket` を拡張した `Chat.Server` クラスで実装されます。 サーバークラスは、`%CSP.WebSocket`のプロパティとメソッドを継承しています。これについては以下の方で説明します。 `Chat.Server` は、クライアントからのメッセージを処理するカスタムメソッドと、クライアントにメッセージをブロードキャストするカスタムメソッドも実装します。 ### *サーバーの起動前処理* `OnPreServer()` は、WebSocketサーバーが作成されて `%CSP.WebSocket` クラスから継承される前に実行されます。 ``` Method OnPreServer() As %Status { set ..SharedConnection=1 if (..WebSocketID '= ""){ set ^Chat.WebSocketConnections(..WebSocketID)="" } else { set ^Chat.Errors($INCREMENT(^Chat.Errors),"no websocketid defined")=$HOROLOG } Quit $$$OK } ``` このメソッドは、`SharedConnection` クラスのパラメーターを1に設定し、WebSocket接続が非同期であり、InterSystems IRISインスタンスとWebゲートウェイ間の接続を定義する複数のプロセスでサポートされることを示します。 `SharedConnection` パラメーターは、`OnPreServer()` でしか変更できません。 また、`OnPreServer()` は、クライアントに関連付けられているWebSocket IDを `^Chat.WebSocketConnections` グローバルに格納します。 ### *Serverメソッド* サーバーが実行するロジックの本文は、`Server()` メソッドに含まれます。 ``` Method Server() As %Status { do ..StatusUpdate(..WebSocketID) for { set data=..Read(.size,.sc,1) if ($$$ISERR(sc)){ if ($$$GETERRORCODE(sc)=$$$CSPWebSocketTimeout) { //$$$DEBUG("no data") } if ($$$GETERRORCODE(sc)=$$$CSPWebSocketClosed){ kill ^Chat.WebSocketConnections(..WebSocketID) do ..RemoveUser($g(^Chat.Users(..WebSocketID))) kill ^Chat.Users(..WebSocketID) quit // Client closed WebSocket } } else{ if data["User"{ do ..AddUser(data,..WebSocketID) } else { set mid=$INCREMENT(^Chat.Messages) set ^Chat.Messages(mid)=data do ..ProcessMessage(mid) } } } Quit $$$OK } ``` このメソッドは、クライアントからの受信メッセージを読み取り(`%CSP.WebSockets` クラスの `Read` メソッド)、取得したJSONオブジェクトを `^Chat.Messages` グローバルに追加し、接続されているその他すべてのチャットクライアントにメッセージを転送するための `ProcessMessage()` を呼び出します。 ユーザーがチャットウィンドウを閉じると(つまり、サーバーへのWebSocket接続が終了すると)、`Server()` メソッドの `Read` の呼び出しによって、それが評価するエラーコードが `$$$CSPWebSocketClosed` マクロに返され、メソッドはそれに応じて閉鎖の処理に進みます。 ### *メッセージの処理と配信* `ProcessMessage()` は、受信チャットメッセージにメタデータを追加して `SendData()` を呼び出し、メッセージをパラメーターとして渡します。 ``` ClassMethod ProcessMessage(mid As %String) { set msg = ##class(%DynamicObject).%FromJSON($GET(^Chat.Messages(mid))) set msg.Type="Chat" set msg.Sent=$ZDATETIME($HOROLOG,3) do ..SendData(msg) } ``` `ProcessMessage()` は、`^Chat.Messages` グローバルからJSONの書式付きメッセージを取得し、`%DynamicObject` クラスの `%FromJSON` メソッドを使って、そのメッセージをInterSystems IRIS オブジェクトに変換します。 この変換により、メッセージが接続されているすべてのチャットクライアントに転送される前に、データを編集しやすくなります。 `Type` 属性を値「Chat」で追加し、クライアントはこれを使用して、受信メッセージの処理方法を決定しアンス。 `SendData()` は、接続されているその他すべてのチャットクライアントにメッセージを送信します。 ``` ClassMethod SendData(data As %DynamicObject) { set c = "" for { set c = $order(^Chat.WebSocketConnections(c)) if c="" Quit set ws = ..%New() set sc = ws.OpenServer(c) if $$$ISERR(sc) { do ..HandleError(c,"open") } set sc = ws.Write(data.%ToJSON()) if $$$ISERR(sc) { do ..HandleError(c,"write") } } } ``` `SendData()` は、InterSystems IRISオブジェクトをJSON文字列に変換し直し(`data.%ToJSON()`)、すべてのチャットクライアントにメッセージをプッシュします。 `SendData()` は、クライアントとサーバー間のそれぞれの接続に関連付けられたWebSocket IDを `^Chat.WebSocketConnections` グローバルから取得し、そのIDを使って、`%CSP.WebSocket` クラスの `OpenServer` メソッドで、WebSocket接続を開きます。 `OpenServer` メソッドを使ってこの処理を実行できるのは、WebSocket接続が非同期であるからです。IRIS-Webゲートウェイの既存のプールからプロセスをプルし、特定のチャットクライアントへのサーバー接続を識別するWebSocket IDを割り当てています。 最後に、 `Write()` `%CSP.WebSocket` メソッドによって、JSON 文字列に変換されたメッセージがクライアントにプッシュされます。 ## まとめ このチャットアプリケーションでは、クライアントとInterSystems IRISをホストするサーバー間にWebScocket接続を確立する方法が示されています。 InterSystems IRISにおけるプロコルとその実装については、引き続き、「はじめに」セクションに記載されているリンクをご覧ください。
お知らせ
Toshihiko Minamoto · 2021年2月18日

IAM 1.5.0.9 がリリースされました

InterSystems API Manager(IAM) バージョン1.5がリリースされました   以前のバージョンからアップグレードできるIAMコンテナはWRCソフトウェア配布サイトのComponents areaからダウンロードすることができます。   ビルド番号はIAM 1.5.0.9-4 です。   InterSystems API Manager 1.5 ではAPIトラフィックの管理や、環境とAPI利用者の統合がさらに簡単になりました。新機能は以下の通りです。   ユーザエクスペリエンスの改善 新たな開発者ポータル Kafka connectivityのサポート   このリリースは、Kong Enterprise バージョン 1.5.0.9 をベースにしています。これまでのIAMリリースにはKong Enterpriseのホワイトラベルバージョンが入っていましたが、このリリースではホワイトラベルなしバージョンが入っています。この変更で、より頻繁にリリースすることができ、 Kongの提供するドキュメントやその他の資産を効果的に活用できるようになりました。   IAM 1.5のドキュメントはこちらです。このドキュメントはIAM固有の部分のみカバーしています。製品のドキュメントからユーザは直接 Kong Enterpriseのドキュメントを参照できます。   IAM 0.34-1 からのアップグレードはこちらのドキュメントで詳細が記載されている3つの中間リリースを通してアップグレードする必要があります。   IAM はdockerコンテナとして知られるOCI (Open Container Initiative) でのみ動作します。 コンテナイメージはOCIに準拠したLinux x86-64、Linux ARM64対応のランタイムエンジンで動作可能です。詳細はサポートプラットホームを参照してください。   よろしくお願いいたします。 Stefan
記事
Hiroshi Sato · 2022年3月23日

現在使用しているリレーショナルデータベースで壁に突き当たっています。インターシステムズのテクノロジを利用することはできますか。

もし現在ご使用のデータベース技術で壁に突き当たっていると感じておられるならば、是非InterSystems IRIS Data Platformへの移行をご検討ください。 (以下IRIS) IRISに移行するに際して、現行のプログラム資産を全て書き換える必要はありません。 IRISに移行する際には、以下の手順で進めることを推奨しております。 アプリケーションコードをそのまま流用し、動作させるために、現在のデータベースからIRISへの移行を行います。 既存のRDBMSのデータ定義(DDL文で記述されたもの)をIRISに取り込むことで、リレーショナルとオブジェクトの両モデルからアクセスが可能となるため、必要に応じてオブジェクト・アクセスが妥当である処理に対しては、アプリケーションプログラムの修正など、対応策が選択できます。 さらにXMLやJSONなどのドキュメント形式のデータの取り扱いも容易ですので、RestFullなアプリケーション構築にも向いています。 また、IRISには習得が容易でデータベースエンジンと一体化したスクリプト言語「InterSystems ObjectScript」が用意されているので、処理の一部をサーバ側ロジックとしてストアドプロシージャ化することによってデータベース処理を効率化するなど、様々な対応策を検討することができます。 バージョン2021.2からは、Embedded Pythonのサポートが追加され、ObjectScriptと同様に同一プロセス空間からデータベースアクセスが可能となり、Pythonプログラムからのデータベースアクセスが大幅に改善されました。
記事
Hiroshi Sato · 2021年10月19日

システムを個別に繋ぐ方法とIRISで接続する方法で何が違うのですか?

これはInterSystems FAQ サイトの記事です。 2つのシステムをつなぐだけだったら、わざわざInterSystems IRIS Data Platform(以下IRISと表記)のようなものを仲介させるのは無駄に思えるかもしれません。 ですが、システムの接続は複数システム間に跨るのが一般的です。 そしてシステムの数が増えるにつれ、その接続は複雑になっていき、接続のタイミング、接続プロジェクトの進行管理などが重荷になっていきます。 また各接続は時が経つにつれ変化するのが一般的で、そういうことが起こると双方のシステムにその都度修正が必要になります。 相互依存性が高まるわけです。 また時が経つにつれ各システムが本来持っている機能と接続に関わる処理が混在するケースが多く、変更の影響範囲が多岐に渡ってしまい、 ちょっとした修正でも影響範囲の特定が困難となり、修正作業が膨大になるケースがあります。 IRISを使ってシステム接続を中継させることにより、接続に関する様々な雑用をIRISが担うようになれば、やがて接続の標準化が促進され、各システムには全く変更を加えることなく接続が可能になり、何か変更があった場合にも影響範囲が限定され、その変更作業に必要な工数を最小化できます。 さらに様々なシステムが生成するデータがIRIS上に流れることになるので、その情報を整理して統合データベースを構築することも簡単に実現できます。
記事
Toshihiko Minamoto · 2022年8月17日

%SYSTEM.Encryption クラスを習得する

InterSystems IRIS には、暗号化、復号化、およびハッシュ操作の優れたサポートが備わっています。 クラス %SYSTEM.Encryption(https://docs.intersystems.com/iris20212/csp/documatic/%25CSP.Documatic.cls?LIBRARY=%25SYS&PRIVATE=1&CLASSNAME=%25SYSTEM.Encryption)の中には、市場に出回っている主なアルゴリズムのクラスメソッドがあります。 ## IRIS アルゴリズムと暗号化/復号化の方式 ご覧のとおり、操作は鍵に基づいており、3 つのオプションが含まれます。 * **対称鍵**: 暗号化と復号化の操作を実行する部分で同じ秘密鍵が使用されます。 * **非対称鍵**: 暗号化と復号化の操作を実行する部分で、暗号化に同じ秘密鍵が使用されますが、 復号化においては、各パートナーが秘密鍵を所有します。 この鍵は身元を証明するものであるため、他人と共有することはできません。 * **ハッシュ**: 暗号化だけが必要で、復号化が不要である場合に使用されます。強力なユーザーパスワードを保存する際に一般的なアプローチです。   ## 対称暗号化と非対称暗号化の違い * 対称暗号化では、メッセージを受信する必要のある人の間で単一の鍵を共有して使用しますが、非対称暗号化では、通信時に公開鍵と秘密鍵のペアを使用してメッセージの暗号化と復号化を行います。 * 対称暗号化は古いテクニックであるのに対し、非対称暗号化は比較的最近のテクニックです。 * 非対称暗号化は、対称暗号化モデルで鍵を共有する必要性に関わる固有の問題を補完するために導入されました。公開鍵と秘密鍵のペアを使用することで、鍵を共有する必要がなくなっています。 * 非対称暗号化には、対称暗号化よりも比較的時間がかかります。   主な違い 対称暗号化 非対称暗号化 暗号文のサイズ 元のプレーンテキストファイルより小さい暗号文。 元のプレーンテキストファイルより大きい暗号文。 データサイズ ビッグデータの送信に使用される。 スモールデータの送信に使用される。 リソース使用率 対称鍵暗号化は、リソース使用率が低い場合に機能します。 非対称暗号化では、大量のリソースを消費する必要があります。 鍵の長さ 128 または 256 ビットの鍵サイズ。 RSA 2048 ビット以上の鍵サイズ。 セキュリティ 暗号化に単一の鍵を使用するため、セキュリティが低下。 暗号化と復号化を 2 つの異なる鍵で行うため、はるかに安全。 鍵の数 対称暗号化では、暗号化と復号化に単一の鍵を使用する。 非対称暗号化では、暗号化と復号化に 2 つの異なる鍵を使用する。 テクニック 古いテクニック。 最新のテクニック。 機密性 暗号化と復号化に使用される単一の鍵には、その鍵が改ざんされる可能性がある。 暗号化と復号化で個別に 2 つの鍵が作成されるため、鍵を共有する必要がない。 速度 対称暗号化は高速な手法。 非対称暗号化は速度が低下する。 アルゴリズム RC4、AES、DES、3DES、および QUAD。 RSA、Diffie-Hellman、ECC アルゴリズム。 出典: https://www.ssl2buy.com/wiki/symmetric-vs-asymmetric-encryption-what-are-differences  ## %SYSTEM.Encryption クラスを使用して暗号化、復号化、ハッシュを実行 IRIS の暗号化、復号化、およびハッシュ操作のサポートを使用するには、https://github.com/yurimarx/cryptography-samples にアクセスし、以下の手順に従ってください。 1. リポジトリを任意のローカルディレクトリに Clone/git pull します。 $ git clone https://github.com/yurimarx/cryptography-samples.git 2. このディレクトリで Docker ターミナルを開き、以下を実行します。 $ docker-compose build 3. IRIS コンテナを実行します。 $ docker-compose up -d 4. IRIS ターミナルを開きます。 $ docker-compose exec iris iris session iris -U IRISAPP IRISAPP> 5. 非対称暗号化の RSA Encrypt を実行するには、以下を実行します。 IRISAPP>Set ciphertext = ##class(dc.cryptosamples.Samples).DoRSAEncrypt("InterSystems") IRISAPP>Write ciphertext Ms/eR7pPmE39KBJu75EOYIxpFEd7qqoji61EfahJE1r9mGZX1NYuw5i2cPS5YwE3Aw6vPAeiEKXF rYW++WtzMeRIRdCMbLG9PrCHD3iQHfZobBnuzx/JMXVc6a4TssbY9gk7qJ5BmlqRTU8zNJiiVmd8 pCFpJgwKzKkNrIgaQn48EgnwblmVkxSFnF2jwXpBt/naNudBguFUBthef2wfULl4uY00aZzHHNxA bi15mzTdlSJu1vRtCQaEahng9ug7BZ6dyWCHOv74O/L5NEHI+jU+kHQeF2DJneE2yWNESzqhSECa ZbRjjxNxiRn/HVAKyZdAjkGQVKUkyG8vjnc3Jw== 6. 非対称復号化の RSA Decrypt を実行するには、以下を実行します。 IRISAPP>Set plaintext = ##class(dc.cryptosamples.Samples).DoRSADecrypt(ciphertext) IRISAPP>Write plaintext InterSystems 7. 非対称暗号化の AES CBC Encrypt を実行するには、以下を実行します。 IRISAPP>Do ##class(dc.cryptosamples.Samples).DoAESCBCEncrypt("InterSystems") 8sGVUikDZaJF+Z9UljFVAA== 8. 対称暗号化の AES CBC Decrypt を行うには、以下を実行します。 IRISAPP>Do ##class(dc.cryptosamples.Samples).DoAESCBCDecrypt("8sGVUikDZaJF+Z9UljFVAA==") InterSystems 9. 古いハッシュアプローチの MD5 hash を実行するには、以下を実行します。 IRISAPP>Do ##class(dc.cryptosamples.Samples).DoHash("InterSystems") rOs6HXfrnbEY5+JBdUJ8hw== 10. 推奨されるハッシュアプローチの SHA hash を実行するには、以下を実行します。 IRISAPP>Do ##class(dc.cryptosamples.Samples).DoSHAHash("InterSystems") +X0hDlyoViPlWOm/825KvN3rRKB5cTU5EQTDLvPWM+E= 11. ターミナルを終了するには、以下を実行します。 HALT または H を入力(大文字と小文字は区別されません) ##   ## ソースコードについて ### 1. 対称鍵について # 対称暗号化/復号化で使用する ENV SECRETKEY=InterSystemsIRIS Dockerfile に、対称操作で秘密鍵として使用される環境鍵が作成されました。   ### 2. 非対称鍵について # 非対称暗号化/復号化で使用する RUN openssl req -new -x509 -sha256 -config example-com.conf -newkey rsa:2048 -nodes -keyout example-com.key.pem -days 365 -out example-com.cert.pem Dockerfile に、非対称操作で使用される秘密鍵と公開鍵が生成されました。   ### 3. 対称暗号化 // 暗号化するための対称鍵の例   ClassMethod DoAESCBCEncrypt(plaintext As %String) As %Status {     // utf-8 に変換     Set text=$ZCONVERT(plaintext,"O","UTF8")         // 秘密鍵を設定     Set secretkey = $system.Util.GetEnviron("SECRETKEY")     Set IV = $system.Util.GetEnviron("SECRETKEY")         // テキストを暗号化     Set text = $SYSTEM.Encryption.AESCBCEncrypt(text, secretkey, IV)     Set ciphertext = $SYSTEM.Encryption.Base64Encode(text)         Write ciphertext } テキストの暗号化に AES CBC Encrypt 操作が使用されました。 Base64 Encode は、プリティ/読み取り可能なテキストとしてユーザーに結果を返します。   ### 4. 対称復号化 // 復号化するための対称鍵の例   ClassMethod DoAESCBCDecrypt(ciphertext As %String) As %Status {     // 秘密鍵を設定     Set secretkey = $system.Util.GetEnviron("SECRETKEY")     Set IV = $system.Util.GetEnviron("SECRETKEY")         // テキストを復号化     Set text=$SYSTEM.Encryption.Base64Decode(ciphertext)     Set text=$SYSTEM.Encryption.AESCBCDecrypt(text,secretkey,IV)         Set plaintext=$ZCONVERT(text,"I","UTF8")     Write plaintext } テキストの復号化に AES CBC Decrypt 操作が使用されました。 Base64 Decode は、復号化に使用できるように、暗号化されたテキストをバイナリテキストに返します。   **5. 非対称暗号化** // 暗号化するための非対称鍵の例   ClassMethod DoRSAEncrypt(plaintext As %String) As %Status {     // 公開鍵証明書を取得     Set pubKeyFileName = "/opt/irisbuild/example-com.cert.pem"     Set objCharFile = ##class(%Stream.FileCharacter).%New()     Set objCharFile.Filename = pubKeyFileName     Set pubKey = objCharFile.Read()       // RSA を使って暗号化     Set binarytext = $System.Encryption.RSAEncrypt(plaintext, pubKey)     Set ciphertext = $SYSTEM.Encryption.Base64Encode(binarytext)         Return ciphertext } RSA で暗号化するには、公開鍵ファイルの内容を取得する必要があります。 テキストの暗号化に、RSA Encrypt 操作が使用されました。   ### 6. 非対称復号化 // 復号化するための非対称鍵の例   ClassMethod DoRSADecrypt(ciphertext As %String) As %Status {     // 秘密鍵を取得     Set privKeyFileName = "/opt/irisbuild/example-com.key.pem"     Set privobjCharFile = ##class(%Stream.FileCharacter).%New()     Set privobjCharFile.Filename = privKeyFileName     Set privKey = privobjCharFile.Read()       // 暗号文をバイナリ形式で取得     Set text=$SYSTEM.Encryption.Base64Decode(ciphertext)       // RSA を使って復号化     Set plaintext = $System.Encryption.RSADecrypt(text, privKey)       Return plaintext } RSA で復号化するには、秘密鍵ファイルの内容を取得する必要があります。 テキストの復号化に、RSA Decrypt 操作が使用されました。   ### 7. MD5 を使ったテキストのハッシュ化(古いアプローチ) // ハッシュの例   ClassMethod DoHash(plaintext As %String) As %Status {     // utf-8 に変換     Set text=$ZCONVERT(plaintext,"O","UTF8")         // テキストをハッシュ化     Set hashtext = $SYSTEM.Encryption.MD5Hash(text)         Set base64text = $SYSTEM.Encryption.Base64Encode(hashtext)       // 16 進テキストを以下のベストプラクティスに変換     Set hextext = ..GetHexText(base64text)       // 小文字を使って返す     Write $ZCONVERT(hextext,"L") } MD5 Hash 操作でテキストを暗号化すると、それを復号化することはできません。 MD5 を使ったハッシュ化は、安全でないと見なされているため、新しいプロジェクトには推奨されません。 そのため、この方式は SHA に置き換えられています。 InterSystems IRIS は SHA をサポートしています(次の例で紹介します)。   ### 8. SHA を使ったテキストのハッシュ化(推奨されるアプローチ) この例では、SHA-3 Hash 方式を使用します。 InterSystems のドキュメントによると、この方式は、US Secure Hash Algorithm - 3 を使ってハッシュを生成します。 (詳細は、連邦情報処理規格 202 をご覧ください。) // SHA を使ったハッシュ   ClassMethod DoSHAHash(plaintext As %String) As %Status {     // utf-8 に変換     Set text=$ZCONVERT(plaintext,"O","UTF8")         // テキストをハッシュ化     Set hashtext = $SYSTEM.Encryption.SHA3Hash(256, text)         Set base64text = $SYSTEM.Encryption.Base64Encode(hashtext)       // 16 進テキストを以下のベストプラクティスに変換     Set hextext = ..GetHexText(base64text)       // 小文字を使って返す     Write $ZCONVERT(hextext,"L") } SHA 方式では、ハッシュ操作で使用するビット長を設定できます。 ビット数が多いほど、ハッシュを解読するのがより困難になりますが、 ハッシュ化の処理速度が低下してしまいます。 この例では、256 ビットが使用されました。 ビット長については以下のオプションを選択できます。 * 224(SHA-224) * 256(SHA-256) * 384(SHA-384) * 512(SHA-512)  
記事
Mihoko Iijima · 2023年6月1日

システム連携の自動的な流れの中にユーザからの指示を介入できる「ワークフローコンポーネント」のサンプル

開発者の皆さん、こんにちは。 先日のウェビナーでご紹介した「ワークフローコンポーネント」をお試しいただけるサンプルを公開しました。👉 https://github.com/Intersystems-jp/WorkFlow-DC 《サンプルのテーマ》 店舗で販売している商品に付けるPOPメッセージ候補を予めテーブルに登録できる仕組みが既にある、と仮定しています。 IRISの Interoperability を利用してPOPメッセージ候補が登録されるテーブルに対して一定間隔でSELECT文を実行し、未処理のメッセージを取得します。新たなレコードが存在する場合、ワークフローコンポーネントを利用して担当者に審査を依頼します。 担当者は、ワークフローユーザポータルを使用して、POPメッセージ候補の承認/却下を指示できるようにしています。 ワークフローコンポーネントは、InterSystems IRIS、InterSystems IRIS for Healthでご利用いただけます。 上記サンプルはコンテナを使用していますので、事前に docker 、docker-compose のインストールが必要となりますが、docker-compose up -d の実行だけで準備が整いますのでよろしければお試しください。 なお、サンプルでは、InterSystems IRIS Community edition 2023.1.0 を利用しています。 コミュニティエディションの種類やバージョンについては、InterSystemsコンテナレジストリでご確認いただけます。 サンプルで使用しているDockerfileの1行目にイメージ名を指定していますので、コンテナビルド前に使用されたいイメージにご変更いただければ別のバージョンや IRIS for Health でもお試しいただけます。 InterSystemsコンテナレジストリのご利用方法については、InterSystemsコンテナレジストリ Webユーザインターフェースのお知らせ をご参照ください。 ワークフローコンポーネントでどんなことができるのか?の概要説明については、ウェビナー(オンデマンド再生)をご参照ください。 それでは、サンプルを使用してどのような流れを体験できるか、ご紹介します。 まずは、サンプル(https://github.com/Intersystems-jp/WorkFlow-DC)を git cloneしたら、WorkFlow-DC ディレクトリに移動し、コンテナをビルド+開始します。 docker-compose build docker-compose up -d コンテナ開始後、ワークフローユーザポータルで処理できるデータが4件作成されます。 ワークフローユーザポータルにログイン、またはサンプルのWebアプリ(Flaskアプリ版ユーザポータル)を利用して動作をご確認いただけます。​​​​ 1. ワークフローユーザポータル での確認 管理ポータルでメッセージのトレースを参照される場合は、ワークフローユーザポータルは管理ポータルとは異なるブラウザで開くことをお勧めします。(管理ポータル/ワークフローユーザポータルにアクセスする際、IRIS内ユーザを利用してログインを行うため、ブラウザの種別が同一の場合、毎回ログインしなおす必要があります) 《コンテナ利用時のワークフローユーザポータルのURL》http://localhost:9093/csp/user/_DeepSee.UserPortal.Home.zen?$NAMESPACE=USER&$NAMESPACE=USER& 以下のワークフローユーザでログインしてください。 ユーザ名:ManagerA/パスワード:SYS 2. Flaskアプリ版ユーザポータル での確認 《コンテナ利用時のFlask版アプリのURL》http://localhost:5001 ユーザ名:ManagerA でログインするように作成しています。 このWebアプリケーションでは、開発者コミュニティのサンプル公開サイトであるOpen Echange に公開されている「ワークフローREST API」を利用してワークフロータスク一覧の取得やタスク詳細表示、タスクの処理を行っています。 3. POPメッセージ用テーブルのデータ確認 管理ポータルのSQLメニューを利用します:IRIS管理ポータル SQLメニュー 《コンテナ利用時のURL》http://localhost:9093/csp/sys/exp/%25CSP.UI.Portal.SQL.Home.zen?$NAMESPACE=USER&$NAMESPACE=USER または、管理ポータル(http://localhost:9093/csp/sys/UtilHome.csp)を開き、[システムエクスプローラ] > [SQL] を開き、ネームスペース:USERを選択します。 管理ポータルには以下のユーザ名/パスワードでログインします。 ユーザ名:SuperUser/パスワード:SYS 以下のSQLで販売商品に対するPOPメッセージの申請登録を確認できます。 SQL画面右側の「クエリ実行」タブに以下SELECT文を入力し、「実行」ボタンをクリックすると結果を確認できます。 SELECT Product->PID,Product->ProductName,POPID,Status,Message,TO_CHAR(StartDate,'YYYY-MM-DD') As StartDate, Period,RejectedReason, Done FROM ISJFoods_Tbl.POP 4. メッセージの確認方法 IRISの管理ポータル、プロダクション構成画面は以下URLでアクセスできます。 IRIS管理ポータル 《コンテナ利用時のURL》http://localhost:9093/csp/sys/UtilHome.csp プロダクション構成画面 《コンテナ利用時のURL》http://localhost:9093/csp/user/EnsPortal.ProductionConfig.zen?$NAMESPACE=USER&$NAMESPACE=USER& または、管理ポータル(http://localhost:9093/csp/sys/UtilHome.csp)を開き [Interoperability] > USERネームスペース選択 > [構成する] > [プロダクション] をクリックします。 メッセージの確認手順 (1) プロダクション構成画面にアクセスします。 サービス:POPメッセージSQL抽出 の文字の付近をクリックし、画面右の「メッセージ」タブを選択します。 (2) 処理したいメッセージを選択します。 コンテナ開始段階で4件のメッセージが参照できるので、ヘッダ列にある番号をクリックし、メッセージのトレース画面を開きます(以下の図は開いた後の画面です)。 トレースにある[2]のメッセージをクリックした後、画面右の「コンテンツ」タブを開き、 以下タグのデータを確認します。 <_Message></_Message> と <_Subject></_Subject> この画面は、ワークフローユーザがタスクを処理した後の確認にも使用するため、開いたままとします。 (3) ワークフローユーザポータル、またはFlaskアプリ上で(2)で確認した情報と同じリストを探し処理します。 ワークフローユーザポータルの場合は、対象行を選択します。 Flaskアプリの場合は「審査する」ボタンをクリックします。 承認か却下ボタンをクリックします。 (4) ユーザ指示後のトレースを確認します。 (2)で確認したトレースをリロードします。 待機していた処理がユーザからの指示により、再開していることがわかります。([3]のメッセージをクリックすると画面右の「コンテンツ」タブでユーザが指示したときのボタン情報を確認できます) ✅ POPメッセージ審査完了通知(Teams)をご利用いただく場合 コンテナ開始時点では、POPメッセージ審査完了通知(Teams)は無効になっています。Teamsの任意チャネルに対して「Incoming Webhook」の設定を行ってください。 設定後、以下設定欄に必要な情報をご記入ください。 オペレーション:登録者へ通知 を選択し「設定」タブにある以下設定を作成されたIncoming Webhookに合わせ修正してください。 HTTPサーバ URL teams設定にある「token」 続いて、プロセス:POP審査 のエディタを開き、一番下にある「登録者への通知」アクティビティをクリックし、画面右にある「無効」のチェックを外し、コンパイルボタンをクリックします。 5. メモ もう1度、同じデータを利用してワークフローユーザポータル上で審査したい場合は、IRIS管理ポータル SQLメニューの「クエリ実行」タブで、以下UPDATE文を実行してください。 update ISJFoods_Tbl.POP set Done=0,Status='pending',RejectedReason=null UPDATE文実行後、メッセージの確認方法でご確認ください。 次の記事では、上記内容をお手元のIRISでお試しいただく手順についてご紹介します。
記事
Mihoko Iijima · 2021年3月9日

指定テーブルの全フィールドをSQLで取得する方法

これは InterSystems FAQ サイトの記事です。 INFORMATION_SCHEMA スキーマを使用して取得できます。 INFORMATION_SCHEMA はシステム用スキーマのため、デフォルトでは管理ポータルの SQL メニューに表示されません。 表示させる方法は以下の通りです。 管理ポータル→システムエクスプローラ→SQL メニューを開きます。 スキーマのプルダウン左にある「システム」をチェックします。 スキーマのプルダウンから INFORMATION_SCHEMA を選択します。 指定のテーブル(Test.Person)に対するID、フィールド名(COLUMN_NAME)、データタイプ(DATA_TYPE)、説明(DESCRIPTION)を取得するSQLは以下の通りです。 SELECT ID,COLUMN_NAME,DATA_TYPE,DESCRIPTION FROM INFORMATION_SCHEMA.COLUMNS where TABLE_SCHEMA='Test' AND TABLE_NAME='Person' 関連するFAQトピックもご参照ください:「プログラムから、クラス定義に記述されたプロパティ定義を取得する方法はありますか?」
記事
Hiroshi Sato · 2021年10月7日

ジャーナルレコード中の「時間」の値について

これは InterSystems FAQ サイトの記事です。ジャーナルレコードの「時間」には、ジャーナルバッファを初期化したときの時間が登録されています。 ジャーナルレコードの時間は、ジャーナルバッファ毎に記録されているため、同じジャーナルバッファ内のジャーナルレコードはすべて同じ時間になります。 なお、ジャーナルバッファは、64KBのサイズで255個存在していて、1つのジャーナルバッファが満杯になった場合、次のジャーナルバッファへレコードを追加するように順番に使用されます。 ジャーナルレコードの時間は、次のバッファへレコードを追加する前に行われる初期化の時間が記録される仕組みになっています。
記事
Megumi Kakechi · 2021年6月7日

IRIS Data Platformは大量のトラフィック処理に耐えられますか?

これは InterSystems FAQ サイトの記事です。 Question: IRIS Data Platformは大量のトラフィック処理に耐えられますか? Answer: IRIS Data Platformは他のデータベースシステムに比較してデータの処理スピードおよび処理能力の面で優れています。 ESGという外部機関が実際に他社データベース製品とのベンチマークテストを実施した結果に関するレポートを公表しています。 またウルシステムズ社による検証結果も公開されています。 ご参考いただければ幸いです。 ESGによるスピードテストの検証結果 ウルシステムズ社ベンチマーク結果レポート 2022/7/5記事の内容を更新しました。検証結果事例を追加しました。
記事
Makiko Kokubun · 2021年6月30日

動画:IRISを手軽に使う3つの方法

*この動画は、2021年2月に開催された「InterSystems Japan Virtual Summit 2021」のアーカイブです。 VSCodeのObjectScript用エクステンションバージョン1.0がリリースされ、GitやDockerなどの標準技術とIRISを手軽に組み合わせて利用できるようになりました。 開発者コミュニティでは、IRISをもっと簡単に操作いただけるようコンテナ版IRISを利用した開発環境テンプレ―トやObjectScriptパッケージマネージャを公開しています。 この動画では「VSCodeからIRISに接続する方法」「開発環境テンプレートの使い方」「パッケージマネージャの使い方」をご紹介します。 この動画の講演資料(PDF)もご用意しました。動画の中でご紹介している技術資料へのURLは、こちらの資料をご活用ください。
記事
Tomoko Furuzono · 2021年12月13日

グローバル単位でジャーナルのON/OFF設定をする方法

これは、InterSystems FAQサイトの記事です。 グローバル単位でジャーナルのON/OFF設定を行いたい場合は、グローバルマッピング設定で、 ・ジャーナルしたいグローバル ⇒ ジャーナルONのデータベースにマッピング)と、 ・ジャーナルしたくないグローバル ⇒ ジャーナルOFFのデータベースにマッピングを分けるという方法があります。 例えば、一部のグローバルのみジャーナルしたくない場合には、そのグローバルを IRISTEMP/CACHETEMP データベースにグローバルマッピングすることで、そのグローバルはジャーナルされなくなります。※IRISTEMP/CACHETEMP データベースは、ジャーナル対象外のデータベースであるため。 ただし、IRISTEMP/CACHETEMP データベースの内容は、再起動時にクリアされますのでご注意ください。
記事
Megumi Kakechi · 2022年2月23日

ジャーナルファイルの使用量をチェックする方法

これは、InterSystems FAQサイトの記事です。現ジャーナルファイル名の取得は、ジャーナリング API を利用します。 ##class(%SYS.Journal.System).GetCurrentFileName() 現ジャーナルファイルの使用量bytesの取得は、ジャーナリング API を利用します。 ##class(%SYS.Journal.System).GetCurrentFileOffset() 実行例は以下の通りです。 %SYS>Write ##class(%SYS.Journal.System).GetCurrentFileName()c:\journal\20110223.001%SYS>Write ##class(%SYS.Journal.System).GetCurrentFileOffset()1213012 あわせて、以下の関連記事も是非ご覧ください。 ジャーナルファイルを削除する方法 ジャーナルファイルが長時間消されずに残ってしまう原因 コマンドでジャーナルファイルにある特定のグローバル変数を検索する方法 誤って削除したグローバルを復旧させる方法 ジャーナルファイルの内容を管理ポータル以外で参照する方法
記事
Megumi Kakechi · 2021年8月11日

ジャーナルファイルを削除する方法

これは InterSystems FAQ サイトの記事です。 ジャーナルファイルの削除は、自動削除と手動削除が選択できます。 「自動削除」については、以下2つの方法が選択できます。 A) タスクスケジュールを使用して指定時間に自動削除する方法B) オンラインバックアップ使用時、指定回数成功後に自動削除する方法 A) タスクスケジュールを使用して指定時間に自動削除する方法 インストール時デフォルトで登録されるタスクスケジュール「ジャーナルファイルの削除」を使用して自動削除します。自動削除を行う前に運用環境に合わせて適切な日数分ジャーナルを保持するよう、ジャーナルファイルの設定を修正します。 ジャーナルファイルの設定は以下メニューを使用します。【バージョン2011.1以降】  [ホーム] > [システム管理] > [構成] > [システム構成] > [ジャーナル設定]【バージョン5.1~2010.x】 [ホーム] > [構成] > [ジャーナル設定] 「ジャーナル設定画面」にある「ジャーナルファイルの削除」から「この日数後」の設定を使用します。日数の指定はバックアップ期間に合わせて設定します。例えば、バックアップが1週間毎に行われている場合は、バックアップが行なわれる間のジャーナルファイルをを保持する必要があるため、「7」を設定します。 なお、「ジャーナルファイルの削除」のタスクは 12:30am の実行予定でデフォルト登録されています。この時間帯にCachéが停止している場合、タスクは動かない点ご注意ください。 B) オンラインバックアップ使用時、指定回数成功後に自動削除する方法 オンラインバックアップ(タスクスケジュールにあるフル・累積・差分の種別があるバックアップ、またはシステムオペレーションメニュー以下にあるバックアップメニューからのバックアップ)の指定回数成功後にバックアップ開始前のジャーナルファイルを自動的に削除します。※オンラインバックアップについて詳細は、関連トピックをご参照ください。 ***続いて、ジャーナルファイルを「手動で削除」する方法は以下の通りです。 %SYSネームスペースに移動して、PURGE^JOURNAL ルーチンを使用するか、または^JOURNAL メニューの Option プロンプトで「6」を指定して削除します。 PURGE^JOURNAL ルーチンを使用して削除する方法は以下の通りです 実行例では、「1」の「Purge any journal NOT required for transaction rollback or crash recovery」のオプションはジャーナルファイルにトランザクション開始中の情報が含まれている、またはクラッシュ後のリカバリに使用する情報が含まれるているファイルの削除は行わず、それ以外のジャーナルファイルを削除するオプションを選択しています。 USER>zn "%SYS" %SYS>do ^JOURNAL 1) Begin Journaling (^JRNSTART) 2) Stop Journaling (^JRNSTOP) 3) Switch Journal File (^JRNSWTCH) 4) Restore Globals From Journal (^JRNRESTO) 5) Display Journal File (^JRNDUMP) 6) Purge Journal Files (PURGE^JOURNAL) 7) Edit Journal Properties (^JRNOPTS) 8) Activate or Deactivate Journal Encryption (ENCRYPT^JOURNAL()) 9) Display Journal status (Status^JOURNAL)10) -not available-11) -not available-12) Journal catch-up for mirrored databases (MirrorCatchup^JRNRESTO)13) -not available- Option? 6 1) Purge any journal NOT required for transaction rollback or crash recovery2) Purge journals based on existing criteria (2 days or 2 backups) Option? 1 以下のジャーナルファイルが削除されました (新しいものから古いものの順番で表示されます): 3. c:\intersystems\iris\mgr\journal\20210811.0012. c:\intersystems\iris\mgr\journal\20210810.0011. c:\intersystems\iris\mgr\journal\20210806.005 1) Begin Journaling (^JRNSTART) 2) Stop Journaling (^JRNSTOP) 3) Switch Journal File (^JRNSWTCH) 4) Restore Globals From Journal (^JRNRESTO) 5) Display Journal File (^JRNDUMP) 6) Purge Journal Files (PURGE^JOURNAL) 7) Edit Journal Properties (^JRNOPTS) 8) Activate or Deactivate Journal Encryption (ENCRYPT^JOURNAL()) 9) Display Journal status (Status^JOURNAL)10) -not available-11) -not available-12) Journal catch-up for mirrored databases (MirrorCatchup^JRNRESTO)13) -not available- Option? //Enterを押すとメニューが終了します。 詳細については、以下ドキュメントページをご参照ください。 PURGE^JOURNALについて【IRIS】PURGE^JOURNALについて 以下の関連トピックもあわせてご覧ください。 【FAQ】データベースのバックアップ方法についてジャーナルファイルが長時間消されずに残ってしまう原因
記事
Toshihiko Minamoto · 2022年3月17日

IRIS Web アプリケーションからの GitHub アカウントによる OAuth2 認証

![](/sites/default/files/inline/images/images/image(3117).png) この記事では、以下のオンラインデモを通じ、GitHub アカウントを使用した OAuth2 認証の基本を説明します。 https://dappsecurity.demo.community.intersystems.com/csp/user/index.csp(SuperUser | SYS) ## 推奨事項: * OAuth2 の概要: https://learning.intersystems.com/course/view.php?id=252 * ドキュメント: [OAuth2 クライアントとして InterSystems IRIS Web アプリケーションを使用する](https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=GOAUTH_client) * 記事: https://community.intersystems.com/post/intersystems-iris-open-authorization-framework-oauth-20-implementation-part-1 目的を達成するために必要な 3 つのステップ: * ステップ 1: GitHub 認証サーバーにアプリケーションを登録する * ステップ 2: InterSystems 管理ポータルから OAuth 2.0 クライアントを構成する * ステップ 3: GitHub アカウントでログインするための API を呼び出す それでは始めましょう。  ## ステップ 1: GitHub 認証サーバーにアプリケーションを登録する GitHub 認証サーバーにアプリケーションを登録するには、GitHub アカウントが必要です。  GitHub アカウントにログインして https://github.com/settings/developers に移動し、[OAuth Apps(OAuth アプリ)]タブで[New OAuth App(新しい OAuth アプリ)]ボタンをクリックします。 ![](/sites/default/files/inline/images/images/image(3134).png)   アプリケーション名、ホームページ URL、説明、および認証コールバック URL を入力します。 認証コールバック URL は **OAuth2.Response.cls** クラス({domain}/csp/sys/oauth2/OAuth2.Response.cls)を参照する必要があることに注意してください。 [Register Application(アプリケーションを登録)]をクリックします。 ![](/sites/default/files/inline/images/images/image(3135).png) すると、詳細ページが開きます。 [Generate a new client secret(新しいクライアントシークレットを生成)]をクリックし、IRIS OAuth2 クライアントを構成する際に使用するクライアント ID と秘密鍵を保存します。 ![](/sites/default/files/inline/images/images/image(3136).png) アプリケーションが登録されました。 ![](/sites/default/files/inline/images/images/image(3137).png) ## ステップ 2: InterSystems 管理ポータルから OAuth 2.0 クライアントを構成する [[システム](https://dappsecurity.demo.community.intersystems.com/csp/sys/%25CSP.Portal.Home.zen)]>[[セキュリティ管理](https://dappsecurity.demo.community.intersystems.com/csp/sys/%25CSP.Portal.Home.zen)]>[[OAuth 2.0 クライアント](https://dappsecurity.demo.community.intersystems.com/csp/sys/sec/%25CSP.UI.Portal.OAuth2.Client.ServerList.zen)]に移動し、[サーバーの説明を作成]ボタンをクリックします。 ![](/sites/default/files/inline/images/images/image(3138).png) 上部にある[手動]ボタンをクリックし、以下の詳細を入力してサーバーの説明を保存します。 ![](/sites/default/files/inline/images/images/image(3139).png) [[システム](https://dappsecurity.demo.community.intersystems.com/csp/sys/%25CSP.Portal.Home.zen)]>[[セキュリティ管理](https://dappsecurity.demo.community.intersystems.com/csp/sys/%25CSP.Portal.Home.zen)]>[[OAuth 2.0 クライアント](https://dappsecurity.demo.community.intersystems.com/csp/sys/sec/%25CSP.UI.Portal.OAuth2.Client.ServerList.zen)]に戻り、[クライアント構成]をクリックします。 ![](/sites/default/files/inline/images/images/image(3140).png) [一般]タブに詳細を入力します。 クライアントリダイレクト URL は、アプリケーションを GitHub に登録した際に入力した認証コールバック URLと同じであることに注意してください。 ![](/sites/default/files/inline/images/images/image(3141).png) [クライアント資格情報]に、アプリケーションを GitHub に登録した際に生成したクライアント ID とクライアントシークレットを入力し、クライアント構成を保存します。 ![](/sites/default/files/inline/images/images/image(3142).png) ## ステップ 3: GitHub アカウントでログインするための API を呼び出す オンラインデモ(https://dappsecurity.demo.community.intersystems.com/csp/user/index.csp)に移動し、 SuperUser | SYS でログインします。 トップメニューから[Login with GitHub(GitHub でログイン)]をクリックします。 ![](/sites/default/files/inline/images/images/image(3143).png) これで、Oauth.cls ページが開きます。 サインインを試す前に、必ず GitHub からログアウトしてください。 [GitHub Sign In(GitHub サインイン)]をクリックします。 ![](/sites/default/files/inline/images/images/image(3144).png) システムは **%SYS.OAuth2.Authorization** クラス(https://docs.intersystems.com/latest/csp/documatic/%25CSP.Documatic.cls?&LIBRARY=%25SYS&PRIVATE=1&CLASSNAME=%25SYS.OAuth2.Authorization)の **GetAuthorizationCodeEndpoint** メソッドを使用して、GitHub 認証サーバーに移動します。 ![](/sites/default/files/inline/images/images/image(3145).png) ログインに成功すると、システムは OauthRe.cls ページにリダイレクトします。 ![](/sites/default/files/inline/images/images/image(3147).png) コードは https://github.com/mwaseem75/Data\_APP\_Security のリポジトリから入手できます。   以上です!  
記事
Megumi Kakechi · 2022年5月31日

Embedded Python で IRIS グローバル($LB) を Pandas Dataframe に変換する方法

InterSystems IRIS 2021.2 のバージョンより、Embedded Python を使用できるようになりました。 Embedded Python で Excel のデータを IRIS グローバルに格納する方法 では pandas.DataFrame のデータを InterSystems IRIS グローバルに保存する方法をご紹介しました。こちらの記事では、その逆の「InterSystems IRIS グローバル($LB) を pandas.DataFrame に変換する」方法をご紹介します。 以下のようなグローバルを、Embedded Python を使用して DataFrame に変換します。 USER>zwrite ^ISJ ^ISJ(1)=$lb("Name","Age","Address") ^ISJ(2)=$lb("佐藤","50","東京") ^ISJ(3)=$lb("加藤","40","大阪") ^ISJ(4)=$lb("伊藤","30","京都") %Library.GlobalクラスのGetクエリ を使用して取得し、iris.sql.execを使用して DataFrame に格納する方法があります。ただし、こちらの方法はリスト形式($LB)のまま DataFrame に変換します。 USER>do $system.Python.Shell() Python 3.9.5 (default, Apr 15 2022, 01:28:04) [MSC v.1927 64 bit (AMD64)] on win32 Type quit() or Ctrl-D to exit this shell. >>> mysql = "select name,value from %library.global_get('user','^ISJ',,2,2)" >>> resultset = iris.sql.exec(mysql) >>> dataframe = resultset.dataframe() >>> print (dataframe) name value 0 ^ISJ 4 1 ^ISJ(1) $lb("Name","Age","Address") 2 ^ISJ(2) $lb("佐藤","50","東京") 3 ^ISJ(3) $lb("加藤","40","大阪") 4 ^ISJ(4) $lb("伊藤","30","京都") >>> こちらの結果の value を Name, Age, Address に分けて変換したい場合、既存の %Global.cls のクエリで行うことはできないため、 IRIS側で、あらかじめリスト形式($LB)を分解してから処理する か、 Python側で、IRISのリスト形式($LB)のまま格納されたデータを文字列置換などして DataFrame を作り直す のどちらかを行う必要があります。 上記1の「IRIS側で処理する」場合、カスタムクラスクエリ を使用してグローバル内のリストの各データを返すクエリを作成し、それをSQL経由でアクセスする方法が考えられます。カスタムクラスクエリを使用する方法は、SQL文ではなくユーザコードでクラスクエリを記述する方法はありますか? の記事でご紹介しています。 上の記事で紹介しているサンプルクラスを使用して、^ISJ のリストを要素別に抽出するサンプルを作成してみました。 ^ISJの value の結果列が$LB形式で3要素なので、上の記事で使用しているサンプルを以下のように変更します。 ★GFetchクラスメソッド //Set Row=$LB($na(@glvn@(x)),@glvn@(x)) Set Row=$LB($na(@glvn@(x)),$LIST(@glvn@(x),1),$LIST(@glvn@(x),2),$LIST(@glvn@(x),3)) ★Gクエリ // Query G(glvn As %String) As %Query(CONTAINID = 0, ROWSPEC = "Node:%String, Value:%String") [ SqlProc ] Query G(glvn As %String) As %Query(CONTAINID = 0, ROWSPEC = "Node:%String, Value1:%String, Value2:%String, Value3:%String") [ SqlProc ] 実行例は以下のようになります。 USER>do $system.Python.Shell() Python 3.9.5 (default, Apr 15 2022, 01:28:04) [MSC v.1927 64 bit (AMD64)] on win32 Type quit() or Ctrl-D to exit this shell. >>> mysql="select * from SQLUSER.TestStoredProc1_G('^ISJ')" >>> resultset = iris.sql.exec(mysql) >>> dataframe = resultset.dataframe() >>> print (dataframe) node value1 value2 value3 0 ^ISJ(1) Name Age Address 1 ^ISJ(2) 佐藤 50 東京 2 ^ISJ(3) 加藤 40 大阪 3 ^ISJ(4) 伊藤 30 京都 >>> 今回使用したサンプルはこちらにあります 👉https://github.com/Intersystems-jp/GlobalToPandasDataframe ~~~ (2022/06/01現在)日本語対応はしていませんが、以下のような方法もあります。こちらは将来のバージョンで日本語対応予定です。%SYS.Pythonクラスの ToList()メソッドを使用して、IRISリストをPythonリストに変換する方法です。 1.以下のようなクラスを作成します。 ClassMethod toPythonList(gname As %String, i As %Integer) As %SYS.Python { quit ##class("%SYS.Python").ToList(@gname@(i)) } ClassMethod getDataFrame(gname As %String) [ Language = python ] { import iris import pandas as pd g = iris.gref(gname) cnt=g[None] newlist=[] for i in range(1,cnt+1): datalist=iris.cls(__name__).toPythonList(gname, i) newlist.append(datalist) newdf=pd.DataFrame(newlist[1:cnt],columns=[newlist[0][0],newlist[0][1],newlist[0][2]]) print(newdf) } 2.次のように実行します。使用するのは ^ISJ2 のような英数字のみのデータが含まれるリスト形式のグローバルです。 USER>zw ^ISJ2 ^ISJ2=4 ^ISJ2(1)=$lb("Name","Age","Address") ^ISJ2(2)=$lb("Sato","50","Tokyo") ^ISJ2(3)=$lb("Kato","40","Osaka") ^ISJ2(4)=$lb("Ito","30","Kyoto") USER>do ##class(%SYS.Python).Shell() Python 3.9.5 (default, Apr 15 2022, 01:28:04) [MSC v.1927 64 bit (AMD64)] on win32 Type quit() or Ctrl-D to exit this shell. >>> iris.cls('User.PythonTest').getDataFrame('^ISJ2') Name Age Address 0 Sato 50 Tokyo 1 Kato 40 Osaka 2 Ito 30 Kyoto